<!-- Copyright (C) 2003 Red Hat, Inc. -->
|
<!-- Copyright (C) 2003 Red Hat, Inc. -->
|
<!-- This material may be distributed only subject to the terms -->
|
<!-- This material may be distributed only subject to the terms -->
|
<!-- and conditions set forth in the Open Publication License, v1.0 -->
|
<!-- and conditions set forth in the Open Publication License, v1.0 -->
|
<!-- or later (the latest version is presently available at -->
|
<!-- or later (the latest version is presently available at -->
|
<!-- http://www.opencontent.org/openpub/). -->
|
<!-- http://www.opencontent.org/openpub/). -->
|
<!-- Distribution of the work or derivative of the work in any -->
|
<!-- Distribution of the work or derivative of the work in any -->
|
<!-- standard (paper) book form is prohibited unless prior -->
|
<!-- standard (paper) book form is prohibited unless prior -->
|
<!-- permission is obtained from the copyright holder. -->
|
<!-- permission is obtained from the copyright holder. -->
|
<HTML
|
<HTML
|
><HEAD
|
><HEAD
|
><TITLE
|
><TITLE
|
>More Features — Clocks and Alarm
|
>More Features — Clocks and Alarm
|
Handlers</TITLE
|
Handlers</TITLE
|
><meta name="MSSmartTagsPreventParsing" content="TRUE">
|
><meta name="MSSmartTagsPreventParsing" content="TRUE">
|
<META
|
<META
|
NAME="GENERATOR"
|
NAME="GENERATOR"
|
CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+
|
CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+
|
"><LINK
|
"><LINK
|
REL="HOME"
|
REL="HOME"
|
TITLE="eCos User Guide"
|
TITLE="eCos User Guide"
|
HREF="ecos-user-guide.html"><LINK
|
HREF="ecos-user-guide.html"><LINK
|
REL="UP"
|
REL="UP"
|
TITLE="Programming With eCos"
|
TITLE="Programming With eCos"
|
HREF="user-guide-programming.html"><LINK
|
HREF="user-guide-programming.html"><LINK
|
REL="PREVIOUS"
|
REL="PREVIOUS"
|
TITLE="A Sample Program with Two Threads"
|
TITLE="A Sample Program with Two Threads"
|
HREF="sample-twothreads.html"><LINK
|
HREF="sample-twothreads.html"><LINK
|
REL="NEXT"
|
REL="NEXT"
|
TITLE="The eCos Configuration Tool"
|
TITLE="The eCos Configuration Tool"
|
HREF="the-ecos-configuration-tool.html"></HEAD
|
HREF="the-ecos-configuration-tool.html"></HEAD
|
><BODY
|
><BODY
|
CLASS="CHAPTER"
|
CLASS="CHAPTER"
|
BGCOLOR="#FFFFFF"
|
BGCOLOR="#FFFFFF"
|
TEXT="#000000"
|
TEXT="#000000"
|
LINK="#0000FF"
|
LINK="#0000FF"
|
VLINK="#840084"
|
VLINK="#840084"
|
ALINK="#0000FF"
|
ALINK="#0000FF"
|
><DIV
|
><DIV
|
CLASS="NAVHEADER"
|
CLASS="NAVHEADER"
|
><TABLE
|
><TABLE
|
SUMMARY="Header navigation table"
|
SUMMARY="Header navigation table"
|
WIDTH="100%"
|
WIDTH="100%"
|
BORDER="0"
|
BORDER="0"
|
CELLPADDING="0"
|
CELLPADDING="0"
|
CELLSPACING="0"
|
CELLSPACING="0"
|
><TR
|
><TR
|
><TH
|
><TH
|
COLSPAN="3"
|
COLSPAN="3"
|
ALIGN="center"
|
ALIGN="center"
|
>eCos User Guide</TH
|
>eCos User Guide</TH
|
></TR
|
></TR
|
><TR
|
><TR
|
><TD
|
><TD
|
WIDTH="10%"
|
WIDTH="10%"
|
ALIGN="left"
|
ALIGN="left"
|
VALIGN="bottom"
|
VALIGN="bottom"
|
><A
|
><A
|
HREF="sample-twothreads.html"
|
HREF="sample-twothreads.html"
|
ACCESSKEY="P"
|
ACCESSKEY="P"
|
>Prev</A
|
>Prev</A
|
></TD
|
></TD
|
><TD
|
><TD
|
WIDTH="80%"
|
WIDTH="80%"
|
ALIGN="center"
|
ALIGN="center"
|
VALIGN="bottom"
|
VALIGN="bottom"
|
></TD
|
></TD
|
><TD
|
><TD
|
WIDTH="10%"
|
WIDTH="10%"
|
ALIGN="right"
|
ALIGN="right"
|
VALIGN="bottom"
|
VALIGN="bottom"
|
><A
|
><A
|
HREF="the-ecos-configuration-tool.html"
|
HREF="the-ecos-configuration-tool.html"
|
ACCESSKEY="N"
|
ACCESSKEY="N"
|
>Next</A
|
>Next</A
|
></TD
|
></TD
|
></TR
|
></TR
|
></TABLE
|
></TABLE
|
><HR
|
><HR
|
ALIGN="LEFT"
|
ALIGN="LEFT"
|
WIDTH="100%"></DIV
|
WIDTH="100%"></DIV
|
><DIV
|
><DIV
|
CLASS="CHAPTER"
|
CLASS="CHAPTER"
|
><H1
|
><H1
|
><A
|
><A
|
NAME="CLOCKS-AND-ALARM-HANDLERS">Chapter 14. More Features — Clocks and Alarm
|
NAME="CLOCKS-AND-ALARM-HANDLERS">Chapter 14. More Features — Clocks and Alarm
|
Handlers</H1
|
Handlers</H1
|
><P
|
><P
|
>If a program wanted to execute a task at a given time, or
|
>If a program wanted to execute a task at a given time, or
|
periodically, it could do it in an inefficient way by sitting in a
|
periodically, it could do it in an inefficient way by sitting in a
|
loop and checking the real-time clock to see if the proper amount of
|
loop and checking the real-time clock to see if the proper amount of
|
time has elapsed. But operating systems usually provide system calls
|
time has elapsed. But operating systems usually provide system calls
|
which allow the program to be informed at the desired time.</P
|
which allow the program to be informed at the desired time.</P
|
><P
|
><P
|
><SPAN
|
><SPAN
|
CLASS="PRODUCTNAME"
|
CLASS="PRODUCTNAME"
|
>eCos</SPAN
|
>eCos</SPAN
|
> provides a rich timekeeping formalism, involving
|
> provides a rich timekeeping formalism, involving
|
<SPAN
|
<SPAN
|
CLASS="emphasis"
|
CLASS="emphasis"
|
><I
|
><I
|
CLASS="EMPHASIS"
|
CLASS="EMPHASIS"
|
>counters</I
|
>counters</I
|
></SPAN
|
></SPAN
|
>, <SPAN
|
>, <SPAN
|
CLASS="emphasis"
|
CLASS="emphasis"
|
><I
|
><I
|
CLASS="EMPHASIS"
|
CLASS="EMPHASIS"
|
>clocks</I
|
>clocks</I
|
></SPAN
|
></SPAN
|
>,
|
>,
|
<SPAN
|
<SPAN
|
CLASS="emphasis"
|
CLASS="emphasis"
|
><I
|
><I
|
CLASS="EMPHASIS"
|
CLASS="EMPHASIS"
|
>alarms</I
|
>alarms</I
|
></SPAN
|
></SPAN
|
>, and <SPAN
|
>, and <SPAN
|
CLASS="emphasis"
|
CLASS="emphasis"
|
><I
|
><I
|
CLASS="EMPHASIS"
|
CLASS="EMPHASIS"
|
>timers</I
|
>timers</I
|
></SPAN
|
></SPAN
|
>. The
|
>. The
|
precise definition, relationship, and motivation of these features is
|
precise definition, relationship, and motivation of these features is
|
beyond the scope of this tutorial, but these examples illustrate how
|
beyond the scope of this tutorial, but these examples illustrate how
|
to set up basic periodic tasks.</P
|
to set up basic periodic tasks.</P
|
><P
|
><P
|
>Alarms are events that happen at
|
>Alarms are events that happen at
|
a given time, either once or periodically. A thread associates an
|
a given time, either once or periodically. A thread associates an
|
alarm handling function with the alarm, so that the function will
|
alarm handling function with the alarm, so that the function will
|
be invoked every time the alarm “goes off”.</P
|
be invoked every time the alarm “goes off”.</P
|
><DIV
|
><DIV
|
CLASS="SECT1"
|
CLASS="SECT1"
|
><H1
|
><H1
|
CLASS="SECT1"
|
CLASS="SECT1"
|
><A
|
><A
|
NAME="SAMPLE-ALARMS">A Sample Program with Alarms</H1
|
NAME="SAMPLE-ALARMS">A Sample Program with Alarms</H1
|
><P
|
><P
|
><TT
|
><TT
|
CLASS="FILENAME"
|
CLASS="FILENAME"
|
>simple-alarm.c</TT
|
>simple-alarm.c</TT
|
> (in
|
> (in
|
the examples directory) is a short program that creates a thread that
|
the examples directory) is a short program that creates a thread that
|
creates an alarm. The alarm is handled by the function
|
creates an alarm. The alarm is handled by the function
|
<TT
|
<TT
|
CLASS="FUNCTION"
|
CLASS="FUNCTION"
|
>test_alarm_func()</TT
|
>test_alarm_func()</TT
|
>, which sets a global
|
>, which sets a global
|
variable. When the main thread of execution sees that the variable has
|
variable. When the main thread of execution sees that the variable has
|
changed, it prints a message.</P
|
changed, it prints a message.</P
|
><DIV
|
><DIV
|
CLASS="EXAMPLE"
|
CLASS="EXAMPLE"
|
><A
|
><A
|
NAME="AEN910"><P
|
NAME="AEN910"><P
|
><B
|
><B
|
>Example 14-1. A sample program that creates an alarm</B
|
>Example 14-1. A sample program that creates an alarm</B
|
></P
|
></P
|
><TABLE
|
><TABLE
|
BORDER="5"
|
BORDER="5"
|
BGCOLOR="#E0E0F0"
|
BGCOLOR="#E0E0F0"
|
WIDTH="70%"
|
WIDTH="70%"
|
><TR
|
><TR
|
><TD
|
><TD
|
><PRE
|
><PRE
|
CLASS="PROGRAMLISTING"
|
CLASS="PROGRAMLISTING"
|
>/* this is a very simple program meant to demonstrate
|
>/* this is a very simple program meant to demonstrate
|
a basic use of time, alarms and alarm-handling functions in eCos */
|
a basic use of time, alarms and alarm-handling functions in eCos */
|
|
|
#include <cyg/kernel/kapi.h>
|
#include <cyg/kernel/kapi.h>
|
|
|
#include <stdio.h>
|
#include <stdio.h>
|
|
|
#define NTHREADS 1
|
#define NTHREADS 1
|
#define STACKSIZE 4096
|
#define STACKSIZE 4096
|
|
|
static cyg_handle_t thread[NTHREADS];
|
static cyg_handle_t thread[NTHREADS];
|
|
|
static cyg_thread thread_obj[NTHREADS];
|
static cyg_thread thread_obj[NTHREADS];
|
static char stack[NTHREADS][STACKSIZE];
|
static char stack[NTHREADS][STACKSIZE];
|
|
|
static void alarm_prog( cyg_addrword_t data );
|
static void alarm_prog( cyg_addrword_t data );
|
|
|
/* we install our own startup routine which sets up
|
/* we install our own startup routine which sets up
|
threads and starts the scheduler */
|
threads and starts the scheduler */
|
void cyg_user_start(void)
|
void cyg_user_start(void)
|
{
|
{
|
cyg_thread_create(4, alarm_prog, (cyg_addrword_t) 0,
|
cyg_thread_create(4, alarm_prog, (cyg_addrword_t) 0,
|
"alarm_thread", (void *) stack[0],
|
"alarm_thread", (void *) stack[0],
|
STACKSIZE, &thread[0], &thread_obj[0]);
|
STACKSIZE, &thread[0], &thread_obj[0]);
|
cyg_thread_resume(thread[0]);
|
cyg_thread_resume(thread[0]);
|
}
|
}
|
|
|
/* we need to declare the alarm handling function (which is
|
/* we need to declare the alarm handling function (which is
|
defined below), so that we can pass it to cyg_alarm_initialize() */
|
defined below), so that we can pass it to cyg_alarm_initialize() */
|
cyg_alarm_t test_alarm_func;
|
cyg_alarm_t test_alarm_func;
|
|
|
/* alarm_prog() is a thread which sets up an alarm which is then
|
/* alarm_prog() is a thread which sets up an alarm which is then
|
handled by test_alarm_func() */
|
handled by test_alarm_func() */
|
static void alarm_prog(cyg_addrword_t data)
|
static void alarm_prog(cyg_addrword_t data)
|
{
|
{
|
cyg_handle_t test_counterH, system_clockH, test_alarmH;
|
cyg_handle_t test_counterH, system_clockH, test_alarmH;
|
cyg_tick_count_t ticks;
|
cyg_tick_count_t ticks;
|
cyg_alarm test_alarm;
|
cyg_alarm test_alarm;
|
unsigned how_many_alarms = 0, prev_alarms = 0, tmp_how_many;
|
unsigned how_many_alarms = 0, prev_alarms = 0, tmp_how_many;
|
|
|
system_clockH = cyg_real_time_clock();
|
system_clockH = cyg_real_time_clock();
|
cyg_clock_to_counter(system_clockH, &test_counterH);
|
cyg_clock_to_counter(system_clockH, &test_counterH);
|
cyg_alarm_create(test_counterH, test_alarm_func,
|
cyg_alarm_create(test_counterH, test_alarm_func,
|
(cyg_addrword_t) &how_many_alarms,
|
(cyg_addrword_t) &how_many_alarms,
|
&test_alarmH, &test_alarm);
|
&test_alarmH, &test_alarm);
|
cyg_alarm_initialize(test_alarmH, cyg_current_time()+200, 200);
|
cyg_alarm_initialize(test_alarmH, cyg_current_time()+200, 200);
|
|
|
/* get in a loop in which we read the current time and
|
/* get in a loop in which we read the current time and
|
print it out, just to have something scrolling by */
|
print it out, just to have something scrolling by */
|
for (;;) {
|
for (;;) {
|
ticks = cyg_current_time();
|
ticks = cyg_current_time();
|
printf("Time is %llu\n", ticks);
|
printf("Time is %llu\n", ticks);
|
/* note that we must lock access to how_many_alarms, since the
|
/* note that we must lock access to how_many_alarms, since the
|
alarm handler might change it. this involves using the
|
alarm handler might change it. this involves using the
|
annoying temporary variable tmp_how_many so that I can keep the
|
annoying temporary variable tmp_how_many so that I can keep the
|
critical region short */
|
critical region short */
|
cyg_scheduler_lock();
|
cyg_scheduler_lock();
|
tmp_how_many = how_many_alarms;
|
tmp_how_many = how_many_alarms;
|
cyg_scheduler_unlock();
|
cyg_scheduler_unlock();
|
if (prev_alarms != tmp_how_many) {
|
if (prev_alarms != tmp_how_many) {
|
printf(" --- alarm calls so far: %u\n", tmp_how_many);
|
printf(" --- alarm calls so far: %u\n", tmp_how_many);
|
prev_alarms = tmp_how_many;
|
prev_alarms = tmp_how_many;
|
}
|
}
|
cyg_thread_delay(30);
|
cyg_thread_delay(30);
|
}
|
}
|
}
|
}
|
|
|
/* test_alarm_func() is invoked as an alarm handler, so
|
/* test_alarm_func() is invoked as an alarm handler, so
|
it should be quick and simple. in this case it increments
|
it should be quick and simple. in this case it increments
|
the data that is passed to it. */
|
the data that is passed to it. */
|
void test_alarm_func(cyg_handle_t alarmH, cyg_addrword_t data)
|
void test_alarm_func(cyg_handle_t alarmH, cyg_addrword_t data)
|
{
|
{
|
++*((unsigned *) data);
|
++*((unsigned *) data);
|
}</PRE
|
}</PRE
|
></TD
|
></TD
|
></TR
|
></TR
|
></TABLE
|
></TABLE
|
></DIV
|
></DIV
|
><P
|
><P
|
>When you run this program (by typing <B
|
>When you run this program (by typing <B
|
CLASS="COMMAND"
|
CLASS="COMMAND"
|
>continue</B
|
>continue</B
|
> at
|
> at
|
the (<SPAN
|
the (<SPAN
|
CLASS="emphasis"
|
CLASS="emphasis"
|
><I
|
><I
|
CLASS="EMPHASIS"
|
CLASS="EMPHASIS"
|
>gdb</I
|
>gdb</I
|
></SPAN
|
></SPAN
|
>) prompt) the output should look like
|
>) prompt) the output should look like
|
this:</P
|
this:</P
|
><TABLE
|
><TABLE
|
BORDER="5"
|
BORDER="5"
|
BGCOLOR="#E0E0F0"
|
BGCOLOR="#E0E0F0"
|
WIDTH="70%"
|
WIDTH="70%"
|
><TR
|
><TR
|
><TD
|
><TD
|
><PRE
|
><PRE
|
CLASS="SCREEN"
|
CLASS="SCREEN"
|
>Starting program: <TT
|
>Starting program: <TT
|
CLASS="REPLACEABLE"
|
CLASS="REPLACEABLE"
|
><I
|
><I
|
>BASE_DIR</I
|
>BASE_DIR</I
|
></TT
|
></TT
|
>/examples/simple-alarm.exe
|
>/examples/simple-alarm.exe
|
Time is 0
|
Time is 0
|
Time is 30
|
Time is 30
|
Time is 60
|
Time is 60
|
Time is 90
|
Time is 90
|
Time is 120
|
Time is 120
|
Time is 150
|
Time is 150
|
Time is 180
|
Time is 180
|
Time is 210
|
Time is 210
|
--- alarm calls so far: 1
|
--- alarm calls so far: 1
|
Time is 240
|
Time is 240
|
Time is 270
|
Time is 270
|
Time is 300
|
Time is 300
|
Time is 330
|
Time is 330
|
Time is 360
|
Time is 360
|
Time is 390
|
Time is 390
|
Time is 420
|
Time is 420
|
--- alarm calls so far: 2
|
--- alarm calls so far: 2
|
Time is 450
|
Time is 450
|
Time is 480</PRE
|
Time is 480</PRE
|
></TD
|
></TD
|
></TR
|
></TR
|
></TABLE
|
></TABLE
|
><DIV
|
><DIV
|
CLASS="NOTE"
|
CLASS="NOTE"
|
><BLOCKQUOTE
|
><BLOCKQUOTE
|
CLASS="NOTE"
|
CLASS="NOTE"
|
><P
|
><P
|
><B
|
><B
|
>Note: </B
|
>Note: </B
|
>When running in a simulator the delays
|
>When running in a simulator the delays
|
might be quite long. On a hardware board (where the clock speed is 100
|
might be quite long. On a hardware board (where the clock speed is 100
|
ticks/second) the delays should average to about 0.3 seconds (and 2
|
ticks/second) the delays should average to about 0.3 seconds (and 2
|
seconds between alarms). In simulation, the delay will depend on the
|
seconds between alarms). In simulation, the delay will depend on the
|
speed of the host processor and will almost always be much slower than
|
speed of the host processor and will almost always be much slower than
|
the actual board. You might want to reduce the delay parameter when
|
the actual board. You might want to reduce the delay parameter when
|
running in simulation.</P
|
running in simulation.</P
|
></BLOCKQUOTE
|
></BLOCKQUOTE
|
></DIV
|
></DIV
|
><P
|
><P
|
>Here are a few things you might notice about this program:</P
|
>Here are a few things you might notice about this program:</P
|
><P
|
><P
|
></P
|
></P
|
><UL
|
><UL
|
><LI
|
><LI
|
><P
|
><P
|
>It used the <TT
|
>It used the <TT
|
CLASS="FUNCTION"
|
CLASS="FUNCTION"
|
>cyg_real_time_clock()</TT
|
>cyg_real_time_clock()</TT
|
> function;
|
> function;
|
this always returns a handle to the default system real-time clock. </P
|
this always returns a handle to the default system real-time clock. </P
|
></LI
|
></LI
|
><LI
|
><LI
|
><P
|
><P
|
>Clocks are based on counters, so the function <TT
|
>Clocks are based on counters, so the function <TT
|
CLASS="FUNCTION"
|
CLASS="FUNCTION"
|
>cyg_alarm_create()</TT
|
>cyg_alarm_create()</TT
|
>
|
>
|
uses a counter handle. The program used the function
|
uses a counter handle. The program used the function
|
<TT
|
<TT
|
CLASS="FUNCTION"
|
CLASS="FUNCTION"
|
>cyg_clock_to_counter()</TT
|
>cyg_clock_to_counter()</TT
|
> to strip the clock handle
|
> to strip the clock handle
|
to the underlying counter handle. </P
|
to the underlying counter handle. </P
|
></LI
|
></LI
|
><LI
|
><LI
|
><P
|
><P
|
>Once the alarm is created it is
|
>Once the alarm is created it is
|
initialized with <TT
|
initialized with <TT
|
CLASS="FUNCTION"
|
CLASS="FUNCTION"
|
>cyg_alarm_initialize()</TT
|
>cyg_alarm_initialize()</TT
|
>, which
|
>, which
|
sets the time at which the alarm should go off, as well as the period
|
sets the time at which the alarm should go off, as well as the period
|
for repeating alarms. It is set to go off at the current time and
|
for repeating alarms. It is set to go off at the current time and
|
then to repeat every 200 ticks. </P
|
then to repeat every 200 ticks. </P
|
></LI
|
></LI
|
><LI
|
><LI
|
><P
|
><P
|
>The alarm handler function
|
>The alarm handler function
|
<TT
|
<TT
|
CLASS="FUNCTION"
|
CLASS="FUNCTION"
|
>test_alarm_func()</TT
|
>test_alarm_func()</TT
|
> conforms to the guidelines for
|
> conforms to the guidelines for
|
writing alarm handlers and other delayed service routines: it does not invoke any
|
writing alarm handlers and other delayed service routines: it does not invoke any
|
functions which might lock the scheduler. This is discussed in detail
|
functions which might lock the scheduler. This is discussed in detail
|
in the <I
|
in the <I
|
CLASS="CITETITLE"
|
CLASS="CITETITLE"
|
><SPAN
|
><SPAN
|
CLASS="PRODUCTNAME"
|
CLASS="PRODUCTNAME"
|
>eCos</SPAN
|
>eCos</SPAN
|
> Reference Manual</I
|
> Reference Manual</I
|
>, in the chapter
|
>, in the chapter
|
<I
|
<I
|
CLASS="CITETITLE"
|
CLASS="CITETITLE"
|
>The <SPAN
|
>The <SPAN
|
CLASS="PRODUCTNAME"
|
CLASS="PRODUCTNAME"
|
>eCos</SPAN
|
>eCos</SPAN
|
> Kernel</I
|
> Kernel</I
|
>.</P
|
>.</P
|
></LI
|
></LI
|
><LI
|
><LI
|
><P
|
><P
|
>There is a <SPAN
|
>There is a <SPAN
|
CLASS="emphasis"
|
CLASS="emphasis"
|
><I
|
><I
|
CLASS="EMPHASIS"
|
CLASS="EMPHASIS"
|
>critical region</I
|
>critical region</I
|
></SPAN
|
></SPAN
|
> in this program:
|
> in this program:
|
the variable <TT
|
the variable <TT
|
CLASS="LITERAL"
|
CLASS="LITERAL"
|
>how_many_alarms</TT
|
>how_many_alarms</TT
|
> is accessed in the
|
> is accessed in the
|
main thread of control and is also modified in the alarm handler. To
|
main thread of control and is also modified in the alarm handler. To
|
prevent a possible (though unlikely) race condition on this variable,
|
prevent a possible (though unlikely) race condition on this variable,
|
access to <TT
|
access to <TT
|
CLASS="LITERAL"
|
CLASS="LITERAL"
|
>how_many_alarms</TT
|
>how_many_alarms</TT
|
> in the principal thread
|
> in the principal thread
|
is protected by calls to <TT
|
is protected by calls to <TT
|
CLASS="FUNCTION"
|
CLASS="FUNCTION"
|
>cyg_scheduler_lock()</TT
|
>cyg_scheduler_lock()</TT
|
> and
|
> and
|
<TT
|
<TT
|
CLASS="FUNCTION"
|
CLASS="FUNCTION"
|
>cyg_scheduler_unlock()</TT
|
>cyg_scheduler_unlock()</TT
|
>. When the scheduler is
|
>. When the scheduler is
|
locked, the alarm handler will not be invoked, so the problem is
|
locked, the alarm handler will not be invoked, so the problem is
|
averted. </P
|
averted. </P
|
></LI
|
></LI
|
></UL
|
></UL
|
></DIV
|
></DIV
|
></DIV
|
></DIV
|
><DIV
|
><DIV
|
CLASS="NAVFOOTER"
|
CLASS="NAVFOOTER"
|
><HR
|
><HR
|
ALIGN="LEFT"
|
ALIGN="LEFT"
|
WIDTH="100%"><TABLE
|
WIDTH="100%"><TABLE
|
SUMMARY="Footer navigation table"
|
SUMMARY="Footer navigation table"
|
WIDTH="100%"
|
WIDTH="100%"
|
BORDER="0"
|
BORDER="0"
|
CELLPADDING="0"
|
CELLPADDING="0"
|
CELLSPACING="0"
|
CELLSPACING="0"
|
><TR
|
><TR
|
><TD
|
><TD
|
WIDTH="33%"
|
WIDTH="33%"
|
ALIGN="left"
|
ALIGN="left"
|
VALIGN="top"
|
VALIGN="top"
|
><A
|
><A
|
HREF="sample-twothreads.html"
|
HREF="sample-twothreads.html"
|
ACCESSKEY="P"
|
ACCESSKEY="P"
|
>Prev</A
|
>Prev</A
|
></TD
|
></TD
|
><TD
|
><TD
|
WIDTH="34%"
|
WIDTH="34%"
|
ALIGN="center"
|
ALIGN="center"
|
VALIGN="top"
|
VALIGN="top"
|
><A
|
><A
|
HREF="ecos-user-guide.html"
|
HREF="ecos-user-guide.html"
|
ACCESSKEY="H"
|
ACCESSKEY="H"
|
>Home</A
|
>Home</A
|
></TD
|
></TD
|
><TD
|
><TD
|
WIDTH="33%"
|
WIDTH="33%"
|
ALIGN="right"
|
ALIGN="right"
|
VALIGN="top"
|
VALIGN="top"
|
><A
|
><A
|
HREF="the-ecos-configuration-tool.html"
|
HREF="the-ecos-configuration-tool.html"
|
ACCESSKEY="N"
|
ACCESSKEY="N"
|
>Next</A
|
>Next</A
|
></TD
|
></TD
|
></TR
|
></TR
|
><TR
|
><TR
|
><TD
|
><TD
|
WIDTH="33%"
|
WIDTH="33%"
|
ALIGN="left"
|
ALIGN="left"
|
VALIGN="top"
|
VALIGN="top"
|
>A Sample Program with Two Threads</TD
|
>A Sample Program with Two Threads</TD
|
><TD
|
><TD
|
WIDTH="34%"
|
WIDTH="34%"
|
ALIGN="center"
|
ALIGN="center"
|
VALIGN="top"
|
VALIGN="top"
|
><A
|
><A
|
HREF="user-guide-programming.html"
|
HREF="user-guide-programming.html"
|
ACCESSKEY="U"
|
ACCESSKEY="U"
|
>Up</A
|
>Up</A
|
></TD
|
></TD
|
><TD
|
><TD
|
WIDTH="33%"
|
WIDTH="33%"
|
ALIGN="right"
|
ALIGN="right"
|
VALIGN="top"
|
VALIGN="top"
|
>The eCos Configuration Tool</TD
|
>The eCos Configuration Tool</TD
|
></TR
|
></TR
|
></TABLE
|
></TABLE
|
></DIV
|
></DIV
|
></BODY
|
></BODY
|
></HTML
|
></HTML
|
|
|