📄 tep134.txt
字号:
state whenever a context switch occurs.
**stack_pointer** This field points to the top of a thread's stack. Whenever a
context switch is about to occur, the thread scheduler calls a
``switch_threads()`` function, pushing the return address onto the current
thread's stack. This function stores the current thread's register state,
replaces the processor's stack pointer with that of a new thread, and finally
restores the register state of the new thread. Once this function returns, the
new thread resumes its execution from the point it was interrupted.
**start_function** This field points to a thread's start function along with a
pointer to a single argument. The application developer must ensure that the
structure the argument points to is not deallocated before the thread's start
function executes. These semantics are similar to those that Unix ``pthreads``
define.
**system_call_block** This field contains a pointer to a structure used when
making system calls into a TOSThreads kernel. This structure is readable by both a
system call wrapper implementation and the TinyOS kernel thread. The section
that follows explains how this structure is used.
4.3 Blocking System Calls
----------------------------------------------------------------------
TOSThreads implements blocking system calls by wrapping existing TinyOS services
inside blocking APIs. These wrappers are responsible for maintaining state
across the non-blocking *split-phase* operations associated with the
underlying TinyOS services. They also transfer control to the TinyOS thread
whenever a user thread invokes a system call. All wrappers are written in nesC
with an additional layer of C code layered on top of them. We refer to the
TOSThreads *standard* C API as the API providing system calls to standard
TinyOS services such as sending packets, sampling sensors, and writing to flash.
Alternative API's (potentially also written in C) can be implemented as well
(e.g. the Tenet API).
A user thread initiates a system call by calling a function in one of the
blocking API wrappers. This function creates a local instance of a
*system call block (SCB)* structure which contains: a unique
'syscall_id' associated with the system call; a pointer to the
'thread' invoking the call; a pointer to the function that TinyOS should
call once it assumes control, and the set of parameters this function should
receive. The SCB is used to exchange data with the TinyOS thread.::
struct syscall {
syscall_id_t syscall_id;
thread_t* thread;
void (*syscall_ptr)(struct syscall*);
void* params;
};
All variables associated with a system call (i.e., the pointer to the SCB and
the parameters passed to the system call itself) can all be allocated on the
local stack of the calling thread at the time of the system call. This is
possible because once the calling thread invokes a system call, it will not
return from the function which instantiates these variables until after the
blocking system call completes. These variables remain on the local thread's
stack throughout the duration of the system call and can therefore be accessed
as necessary.
As discussed in Section 2, making a system call implicitly posts a TinyOS task,
causing the TinyOS thread to immediately wake up and the calling thread to
block. In this way, there can only be *one* outstanding system call at any given
time. Thus, only a *single* TinyOS task is necessary to perform an
applications' system calls. The body of this task simply invokes the function
the 'system_call_block' points to.
The important interfaces and components that implement the functionality
described in this section can be found in ``tos/lib/tosthreads/system`` and
``tos/lib/tosthreads/interfaces``. The important ones to look at are the
``SystemCall`` interface, and the ``SystemCallC`` and ``SystemCallP``
components. Example system call wrappers themselves include
``BlockingStdControlC``, ``BlockingAMSenderC``, etc.
5. Programming Applications
====================================================================
Application written using TOSThreads can be programmed in either nesC or
standard C. In nesC, threads can either be created *statically* or
*dynamically* as a TOSThreads application executes. The primary difference
between the two is that statically allocated threads have their TCB allocated
for them at compile time while dynamic threads have them allocated at run time.
5.1 Static Threads
----------------------------------------------------------------------
Static threads are created by wiring in an instance of a ThreadC component as shown
below. As a parameter to ThreadC, we pass in the desired stack size for the thread.
::
configuration ExampleAppC {
}
implementation {
components MainC, ExampleC;
components new ThreadC(STACK_SIZE);
MainC.Boot <- ExampleC;
ExampleC.Thread -> ThreadC;
}
The ThreadC component provides a ``Thread`` interface for creating and
manipulating static threads from within a nesC module.::
interface Thread {
command error_t start(void* arg);
command error_t stop();
command error_t pause();
command error_t resume();
command error_t sleep(uint32_t milli);
event void run(void* arg);
}
Calling ``start()`` on a thread signals to the TOSThreads thread scheduler that
that thread should begin executing. ``start()`` takes as an argument a pointer
to a data structure to pass to a thread once it starts executing. Calls to
``start()`` return either SUCCESS or FAIL. Upon SUCCESS, the thread is
scheduled for execution, and at some point later the ``run()`` event is
signaled. The body of the run event implements the logic of the thread.
Calling ``stop()`` on a thread signals to the TOSThreads thread scheduler that
that thread should stop executing. Once a thread is stopped it cannot be
restarted. Calls to ``stop()`` return SUCESS if a thread was successfully
stopped, and FAIL otherwise. ``stop()`` MUST NOT be called from within the
thread being stopped; it MUST be called from either the TinyOS thread or another
application thread.
Calling ``pause()`` on a thread signals to the TOSThreads thread scheduler that
that thread should be paused. Pausing a thread is different than stopping it in
that a *paused* thread can be restarted again later by calling ``resume()`` on
it. Underneath, the ``pause()`` command is implemented by calling the thread
scheduler's ``suspendCurrentThread()`` command. Calls to ``pause()`` return
SUCCESS if a thread is paused, and FAIL otherwise. Essentially, ``pause()`` is
used to perform an explicit suspension of the currently running thread.
``pause()`` MUST ONLY be called from within the thread itself that is being
paused. Note that these are exactly the opposite semantics than those used for
``stop()``.
Calling ``resume()`` wakes up a thread previously suspended via the ``pause()``
command. SUCCESS is returned if the thread was successfully resumed, FAIL
otherwise.
Calling ``sleep()`` puts a thread to sleep for the interval specified in its
single 'milli' parameter. ``sleep()`` MUST ONLY be called from within the thread
itself that is being put to sleep. SUCCESS is returned if the thread was
successfully put to sleep, FAIL otherwise.
5.2 Dynamic Threads
----------------------------------------------------------------------
Dynamic threads are created by wiring in an instance of a DynamicThreadC
component as shown below.::
configuration ExampleAppC {
}
implementation {
components MainC, ExampleC;
components DynamicThreadC;
MainC.Boot <- ExampleC;
BlinkC.DynamicThread -> DynamicThreadC;
}
The nesC interface for creating and manipulating dynamic threads is.::
interface DynamicThread {
command error_t create(tosthread_t* t, void (*start_routine)(void*),
void* arg, uint16_t stack_size);
command error_t destroy(tosthread_t* t);
command error_t pause(tosthread_t* t);
command error_t resume(tosthread_t* t);
}
``create()`` is used to create a new dynamic thread. It takes 4 parameters:
't', 'start_routine', 'arg', and 'stack_size'. 't' is pointer to a unique
handler associated with the thread being created. 'start_routine' is the start
function associated with the thread. 'arg' is a pointer to a structure passed
to the start function once the thread has begun executing. 'stack_size' is the
size of the stack to be dynamicaly allocated for the thread. Calls to
``create()`` return either SUCCESS, FAIL, or EALREADY. SUCCESS indiactes that
the thread has been successfully created, FAIL means it could not be created,
and EALREADY indicates that the handler assocaited with the 't' parameter is
associated with an already running thread. Upon SUCCESS, a dynamic thread's TCB
and stack memory are dynamically allocated, and the thread is scheduled for
execution. Its 'start_routine' whill be called once it begins running. UPON
FAIL or EALREADY, no side effects occur.
''destroy()`` is similar to ``stop()`` from a static thread's ``Thread``
interface. It follows all the same semantics as this command, except that it
deallocates the TCB and stack memory associated with a thread before returning.
``pause()`` and ``resume()`` are identical to their counterparts in the
``Thread`` interface.
The API allowing TOSThreads applications to be written in standard C includes a
set of functions that simply wrap the commands provided by the
``DynamicThread`` interface. The following section shows an example of how
these functions are used.
5.3 The Full TOSThreads API
----------------------------------------------------------------------
As mentioned previously, TinyOS services are presented to TOSThreads applications
by wrapping their functionality inside blocking system calls. The number and type
of standard services provided is constantly growing so it doesn't make sense to
try and list them all out. Browse through ``tos/lib/tosthreads/system/`` and
``tos/lib/tosthreads/lib`` to see what services are currently available.
Also, take a look at the various applications found in ``apps/tosthreads`` to see
how these services are used. There are applications written in nesC using both
static and dynamic threads, as well as applications written in standard C.
6. Author Addresses
====================================================================
|
| Kevin Klues
| 284 Gates Hall
| Stanford University
| Stanford, CA 94305-9030
| email - klueska@cs.stanford.edu
|
| Chieh-Jan Liang
| XXX
| XXX
| XXX
| email - cliang4@cs.jhu.edu
|
| Jeongyeup Paek
| XXX
| XXX
| XXX
| email - jpaek@enl.usc.edu
|
| Razvan Musaloiu-E
| XXX
| XXX
| XXX
| email - razvanm@cs.jhu.edu
|
| Ramesh Govindan
| XXX
| XXX
| XXX
| email - ramesh@enl.usc.edu
|
| Andreas Terzis
| XXX
| XXX
| XXX
| email - terzis@cs.jhu.edu
|
| Philip Levis
| 358 Gates Hall
| Stanford University
| Stanford, CA 94305-9030
| email - pal@cs.stanford.edu
|
7. Citations
====================================================================
.. [TEP112] TEP 112: Microcontroller Power Management.
.. [TEP118] TEP 118: Dissemination.
.. [TEP119] TEP 119: Collection.
.. [TEP133] TEP 133: Packet Level Time Synchronization.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -