初始版本
@@ -0,0 +1,9 @@
|
||||
CFLAGS=-O -Wuninitialized -Werror
|
||||
|
||||
all: example-codelock example-buffer example-small
|
||||
|
||||
example-codelock: example-codelock.c pt.h lc.h
|
||||
|
||||
example-buffer: example-buffer.c pt.h lc.h
|
||||
|
||||
example-small: example-small.c pt.h lc.h
|
||||
@@ -0,0 +1,51 @@
|
||||
Protothreads are extremely lightweight stackless threads designed for
|
||||
severely memory constrained systems such as small embedded systems or
|
||||
sensor network nodes. Protothreads can be used with or without an
|
||||
underlying operating system.
|
||||
|
||||
Protothreads provides a blocking context on top of an event-driven
|
||||
system, without the overhead of per-thread stacks. The purpose of
|
||||
protothreads is to implement sequential flow of control without
|
||||
complex state machines or full multi-threading.
|
||||
|
||||
Main features:
|
||||
|
||||
* No machine specific code - the protothreads library is pure C
|
||||
* Does not use error-prone functions such as longjmp()
|
||||
* Very small RAM overhead - only two bytes per protothread
|
||||
* Can be used with or without an OS
|
||||
* Provides blocking wait without full multi-threading or
|
||||
stack-switching
|
||||
* Freely available under a BSD-like open source license
|
||||
|
||||
Example applications:
|
||||
|
||||
* Memory constrained systems
|
||||
* Event-driven protocol stacks
|
||||
* Small embedded systems
|
||||
* Sensor network nodes
|
||||
|
||||
The protothreads library is released under an open source BSD-style
|
||||
license that allows for both non-commercial and commercial usage. The
|
||||
only requirement is that credit is given.
|
||||
|
||||
The protothreads library was written by Adam Dunkels <adam@sics.se>
|
||||
with support from Oliver Schmidt <ol.sc@web.de>.
|
||||
|
||||
More information and new versions can be found at the protothreads
|
||||
homepage:
|
||||
http://www.sics.se/~adam/pt/
|
||||
|
||||
Documentation can be found in the doc/ subdirectory.
|
||||
|
||||
Two example programs illustrating the use of protothreads can be found
|
||||
in this directory:
|
||||
|
||||
example-small.c A small example showing how to use protothreads
|
||||
example-buffer.c The bounded buffer problem with protothreads
|
||||
example-codelock.c A code lock with simulated key input
|
||||
|
||||
To compile the examples, simply run "make".
|
||||
|
||||
|
||||
Adam Dunkels, 3 June 2006
|
||||
@@ -0,0 +1,5 @@
|
||||
Protothreads can in some cases fail to compile under Visual C++
|
||||
version 6.0 due to a bug in the compiler. See the following page for a
|
||||
solution to the problem:
|
||||
|
||||
http://support.microsoft.com/default.aspx?scid=kb;en-us;199057
|
||||
@@ -0,0 +1,229 @@
|
||||
# Doxyfile 1.4.6
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Project related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
PROJECT_NAME = "The Protothreads Library 1.4"
|
||||
PROJECT_NUMBER =
|
||||
OUTPUT_DIRECTORY = .
|
||||
CREATE_SUBDIRS = NO
|
||||
OUTPUT_LANGUAGE = English
|
||||
USE_WINDOWS_ENCODING = NO
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
ABBREVIATE_BRIEF =
|
||||
ALWAYS_DETAILED_SEC = NO
|
||||
INLINE_INHERITED_MEMB = NO
|
||||
FULL_PATH_NAMES = YES
|
||||
STRIP_FROM_PATH = ../
|
||||
STRIP_FROM_INC_PATH =
|
||||
SHORT_NAMES = YES
|
||||
JAVADOC_AUTOBRIEF = YES
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
DETAILS_AT_TOP = YES
|
||||
INHERIT_DOCS = YES
|
||||
SEPARATE_MEMBER_PAGES = NO
|
||||
TAB_SIZE = 8
|
||||
ALIASES =
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
BUILTIN_STL_SUPPORT = NO
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
SUBGROUPING = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Build related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
EXTRACT_ALL = NO
|
||||
EXTRACT_PRIVATE = NO
|
||||
EXTRACT_STATIC = NO
|
||||
EXTRACT_LOCAL_CLASSES = NO
|
||||
EXTRACT_LOCAL_METHODS = NO
|
||||
HIDE_UNDOC_MEMBERS = YES
|
||||
HIDE_UNDOC_CLASSES = YES
|
||||
HIDE_FRIEND_COMPOUNDS = NO
|
||||
HIDE_IN_BODY_DOCS = NO
|
||||
INTERNAL_DOCS = NO
|
||||
CASE_SENSE_NAMES = YES
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
INLINE_INFO = YES
|
||||
SORT_MEMBER_DOCS = YES
|
||||
SORT_BRIEF_DOCS = NO
|
||||
SORT_BY_SCOPE_NAME = NO
|
||||
GENERATE_TODOLIST = YES
|
||||
GENERATE_TESTLIST = YES
|
||||
GENERATE_BUGLIST = NO
|
||||
GENERATE_DEPRECATEDLIST= NO
|
||||
ENABLED_SECTIONS =
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
SHOW_USED_FILES = NO
|
||||
SHOW_DIRECTORIES = NO
|
||||
FILE_VERSION_FILTER =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to warning and progress messages
|
||||
#---------------------------------------------------------------------------
|
||||
QUIET = NO
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_NO_PARAMDOC = NO
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
WARN_LOGFILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
INPUT = pt-mainpage.txt \
|
||||
pt-doc.txt \
|
||||
../pt.h \
|
||||
../pt-sem.h \
|
||||
../lc.h \
|
||||
../lc-switch.h \
|
||||
../lc-addrlabels.h
|
||||
FILE_PATTERNS =
|
||||
RECURSIVE = NO
|
||||
EXCLUDE =
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXCLUDE_PATTERNS =
|
||||
EXAMPLE_PATH = ..
|
||||
EXAMPLE_PATTERNS =
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
IMAGE_PATH =
|
||||
INPUT_FILTER =
|
||||
FILTER_PATTERNS =
|
||||
FILTER_SOURCE_FILES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to source browsing
|
||||
#---------------------------------------------------------------------------
|
||||
SOURCE_BROWSER = YES
|
||||
INLINE_SOURCES = YES
|
||||
STRIP_CODE_COMMENTS = NO
|
||||
REFERENCED_BY_RELATION = YES
|
||||
REFERENCES_RELATION = YES
|
||||
USE_HTAGS = NO
|
||||
VERBATIM_HEADERS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
ALPHABETICAL_INDEX = NO
|
||||
COLS_IN_ALPHA_INDEX = 5
|
||||
IGNORE_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the HTML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = html
|
||||
HTML_FILE_EXTENSION = .html
|
||||
HTML_HEADER =
|
||||
HTML_FOOTER =
|
||||
HTML_STYLESHEET =
|
||||
HTML_ALIGN_MEMBERS = YES
|
||||
GENERATE_HTMLHELP = YES
|
||||
CHM_FILE =
|
||||
HHC_LOCATION =
|
||||
GENERATE_CHI = NO
|
||||
BINARY_TOC = NO
|
||||
TOC_EXPAND = NO
|
||||
DISABLE_INDEX = NO
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
GENERATE_TREEVIEW = YES
|
||||
TREEVIEW_WIDTH = 250
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the LaTeX output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_LATEX = YES
|
||||
LATEX_OUTPUT = latex
|
||||
LATEX_CMD_NAME = latex
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
COMPACT_LATEX = YES
|
||||
PAPER_TYPE = a4
|
||||
EXTRA_PACKAGES =
|
||||
LATEX_HEADER = header.tex
|
||||
PDF_HYPERLINKS = YES
|
||||
USE_PDFLATEX = YES
|
||||
LATEX_BATCHMODE = NO
|
||||
LATEX_HIDE_INDICES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the RTF output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_RTF = NO
|
||||
RTF_OUTPUT = rtf
|
||||
COMPACT_RTF = NO
|
||||
RTF_HYPERLINKS = NO
|
||||
RTF_STYLESHEET_FILE =
|
||||
RTF_EXTENSIONS_FILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the man page output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_MAN = NO
|
||||
MAN_OUTPUT = man
|
||||
MAN_EXTENSION = .3
|
||||
MAN_LINKS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the XML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_XML = NO
|
||||
XML_OUTPUT = xml
|
||||
XML_SCHEMA =
|
||||
XML_DTD =
|
||||
XML_PROGRAMLISTING = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options for the AutoGen Definitions output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the Perl module output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_PERLMOD = NO
|
||||
PERLMOD_LATEX = NO
|
||||
PERLMOD_PRETTY = YES
|
||||
PERLMOD_MAKEVAR_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the preprocessor
|
||||
#---------------------------------------------------------------------------
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = NO
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
SEARCH_INCLUDES = YES
|
||||
INCLUDE_PATH =
|
||||
INCLUDE_FILE_PATTERNS =
|
||||
PREDEFINED = DOXYGEN
|
||||
EXPAND_AS_DEFINED =
|
||||
SKIP_FUNCTION_MACROS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::additions related to external references
|
||||
#---------------------------------------------------------------------------
|
||||
TAGFILES =
|
||||
GENERATE_TAGFILE =
|
||||
ALLEXTERNALS = NO
|
||||
EXTERNAL_GROUPS = YES
|
||||
PERL_PATH = /usr/bin/perl
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
CLASS_DIAGRAMS = NO
|
||||
HIDE_UNDOC_RELATIONS = NO
|
||||
HAVE_DOT = NO
|
||||
CLASS_GRAPH = NO
|
||||
COLLABORATION_GRAPH = YES
|
||||
GROUP_GRAPHS = YES
|
||||
UML_LOOK = NO
|
||||
TEMPLATE_RELATIONS = NO
|
||||
INCLUDE_GRAPH = NO
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
CALL_GRAPH = YES
|
||||
GRAPHICAL_HIERARCHY = YES
|
||||
DIRECTORY_GRAPH = YES
|
||||
DOT_IMAGE_FORMAT = png
|
||||
DOT_PATH =
|
||||
DOTFILE_DIRS =
|
||||
MAX_DOT_GRAPH_WIDTH = 1024
|
||||
MAX_DOT_GRAPH_HEIGHT = 1024
|
||||
MAX_DOT_GRAPH_DEPTH = 0
|
||||
DOT_TRANSPARENT = NO
|
||||
DOT_MULTI_TARGETS = NO
|
||||
GENERATE_LEGEND = YES
|
||||
DOT_CLEANUP = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::additions related to the search engine
|
||||
#---------------------------------------------------------------------------
|
||||
SEARCHENGINE = NO
|
||||
@@ -0,0 +1,7 @@
|
||||
dox:
|
||||
doxygen Doxyfile
|
||||
|
||||
|
||||
pdf: dox
|
||||
(cd latex; $(MAKE) refman.pdf)
|
||||
mv latex/refman.pdf pt-refman.pdf
|
||||
@@ -0,0 +1,52 @@
|
||||
\documentclass[a4paper]{article}
|
||||
\usepackage{a4wide}
|
||||
\usepackage{makeidx}
|
||||
\usepackage{fancyhdr}
|
||||
\usepackage{graphicx}
|
||||
\usepackage{multicol}
|
||||
\usepackage{float}
|
||||
\usepackage{textcomp}
|
||||
\usepackage{alltt}
|
||||
\usepackage{times}
|
||||
\usepackage{epsfig}
|
||||
\ifx\pdfoutput\undefined
|
||||
\usepackage[ps2pdf,
|
||||
pagebackref=true,
|
||||
colorlinks=true,
|
||||
linkcolor=blue
|
||||
]{hyperref}
|
||||
\usepackage{pspicture}
|
||||
\else
|
||||
\usepackage[pdftex,
|
||||
pagebackref=true,
|
||||
colorlinks=true,
|
||||
linkcolor=blue
|
||||
]{hyperref}
|
||||
\fi
|
||||
\usepackage{doxygen}
|
||||
\makeindex
|
||||
\setcounter{tocdepth}{1}
|
||||
\renewcommand{\footrulewidth}{0.4pt}
|
||||
\begin{document}
|
||||
\begin{titlepage}
|
||||
\vspace*{5cm}
|
||||
\begin{center}
|
||||
{\Huge Protothreads}\\
|
||||
\vspace*{1cm}
|
||||
{\LARGE The Protothreads Library 1.3 Reference Manual}\\
|
||||
\vspace*{3cm}
|
||||
{\Large June 2006}\\
|
||||
\vspace*{2cm}
|
||||
\includegraphics[width=6cm]{../sicslogo.pdf}\\
|
||||
\vspace*{1cm}
|
||||
{\Large Adam Dunkels}\\
|
||||
{\Large \texttt{adam@sics.se}}\\
|
||||
\vspace*{1cm}
|
||||
{\LARGE Swedish Institute of Computer Science}\\
|
||||
\vspace*{0.5cm}
|
||||
|
||||
\end{center}
|
||||
\end{titlepage}
|
||||
\pagenumbering{roman}
|
||||
\tableofcontents
|
||||
\pagenumbering{arabic}
|
||||
@@ -0,0 +1,310 @@
|
||||
BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV {
|
||||
font-family: Geneva, Arial, Helvetica, sans-serif;
|
||||
}
|
||||
BODY,TD {
|
||||
font-size: 90%;
|
||||
}
|
||||
H1 {
|
||||
text-align: center;
|
||||
font-size: 160%;
|
||||
}
|
||||
H2 {
|
||||
font-size: 120%;
|
||||
}
|
||||
H3 {
|
||||
font-size: 100%;
|
||||
}
|
||||
CAPTION { font-weight: bold }
|
||||
DIV.qindex {
|
||||
width: 100%;
|
||||
background-color: #e8eef2;
|
||||
border: 1px solid #84b0c7;
|
||||
text-align: center;
|
||||
margin: 2px;
|
||||
padding: 2px;
|
||||
line-height: 140%;
|
||||
}
|
||||
DIV.nav {
|
||||
width: 100%;
|
||||
background-color: #e8eef2;
|
||||
border: 1px solid #84b0c7;
|
||||
text-align: center;
|
||||
margin: 2px;
|
||||
padding: 2px;
|
||||
line-height: 140%;
|
||||
}
|
||||
DIV.navtab {
|
||||
background-color: #e8eef2;
|
||||
border: 1px solid #84b0c7;
|
||||
text-align: center;
|
||||
margin: 2px;
|
||||
margin-right: 15px;
|
||||
padding: 2px;
|
||||
}
|
||||
TD.navtab {
|
||||
font-size: 70%;
|
||||
}
|
||||
A.qindex {
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
color: #1A419D;
|
||||
}
|
||||
A.qindex:visited {
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
color: #1A419D
|
||||
}
|
||||
A.qindex:hover {
|
||||
text-decoration: none;
|
||||
background-color: #ddddff;
|
||||
}
|
||||
A.qindexHL {
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
background-color: #6666cc;
|
||||
color: #ffffff;
|
||||
border: 1px double #9295C2;
|
||||
}
|
||||
A.qindexHL:hover {
|
||||
text-decoration: none;
|
||||
background-color: #6666cc;
|
||||
color: #ffffff;
|
||||
}
|
||||
A.qindexHL:visited { text-decoration: none; background-color: #6666cc; color: #ffffff }
|
||||
A.el { text-decoration: none; font-weight: bold }
|
||||
A.elRef { font-weight: bold }
|
||||
A.code:link { text-decoration: none; font-weight: normal; color: #0000FF}
|
||||
A.code:visited { text-decoration: none; font-weight: normal; color: #0000FF}
|
||||
A.codeRef:link { font-weight: normal; color: #0000FF}
|
||||
A.codeRef:visited { font-weight: normal; color: #0000FF}
|
||||
A:hover { text-decoration: none; background-color: #f2f2ff }
|
||||
DL.el { margin-left: -1cm }
|
||||
.fragment {
|
||||
font-family: Fixed, monospace;
|
||||
font-size: 95%;
|
||||
}
|
||||
PRE.fragment {
|
||||
border: 1px solid #CCCCCC;
|
||||
background-color: #f5f5f5;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 4px;
|
||||
margin-left: 2px;
|
||||
margin-right: 8px;
|
||||
padding-left: 6px;
|
||||
padding-right: 6px;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
DIV.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px }
|
||||
TD.md { background-color: #F4F4FB; font-weight: bold; }
|
||||
TD.mdPrefix {
|
||||
background-color: #F4F4FB;
|
||||
color: #606060;
|
||||
font-size: 80%;
|
||||
}
|
||||
TD.mdname1 { background-color: #F4F4FB; font-weight: bold; color: #602020; }
|
||||
TD.mdname { background-color: #F4F4FB; font-weight: bold; color: #602020; width: 600px; }
|
||||
DIV.groupHeader {
|
||||
margin-left: 16px;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 6px;
|
||||
font-weight: bold;
|
||||
}
|
||||
DIV.groupText { margin-left: 16px; font-style: italic; font-size: 90% }
|
||||
BODY {
|
||||
background: white;
|
||||
color: black;
|
||||
margin-right: 20px;
|
||||
margin-left: 20px;
|
||||
}
|
||||
TD.indexkey {
|
||||
background-color: #e8eef2;
|
||||
font-weight: bold;
|
||||
padding-right : 10px;
|
||||
padding-top : 2px;
|
||||
padding-left : 10px;
|
||||
padding-bottom : 2px;
|
||||
margin-left : 0px;
|
||||
margin-right : 0px;
|
||||
margin-top : 2px;
|
||||
margin-bottom : 2px;
|
||||
border: 1px solid #CCCCCC;
|
||||
}
|
||||
TD.indexvalue {
|
||||
background-color: #e8eef2;
|
||||
font-style: italic;
|
||||
padding-right : 10px;
|
||||
padding-top : 2px;
|
||||
padding-left : 10px;
|
||||
padding-bottom : 2px;
|
||||
margin-left : 0px;
|
||||
margin-right : 0px;
|
||||
margin-top : 2px;
|
||||
margin-bottom : 2px;
|
||||
border: 1px solid #CCCCCC;
|
||||
}
|
||||
TR.memlist {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
P.formulaDsp { text-align: center; }
|
||||
IMG.formulaDsp { }
|
||||
IMG.formulaInl { vertical-align: middle; }
|
||||
SPAN.keyword { color: #008000 }
|
||||
SPAN.keywordtype { color: #604020 }
|
||||
SPAN.keywordflow { color: #e08000 }
|
||||
SPAN.comment { color: #800000 }
|
||||
SPAN.preprocessor { color: #806020 }
|
||||
SPAN.stringliteral { color: #002080 }
|
||||
SPAN.charliteral { color: #008080 }
|
||||
.mdTable {
|
||||
border: 1px solid #868686;
|
||||
background-color: #F4F4FB;
|
||||
}
|
||||
.mdRow {
|
||||
padding: 8px 10px;
|
||||
}
|
||||
.mdescLeft {
|
||||
padding: 0px 8px 4px 8px;
|
||||
font-size: 80%;
|
||||
font-style: italic;
|
||||
background-color: #FAFAFA;
|
||||
border-top: 1px none #E0E0E0;
|
||||
border-right: 1px none #E0E0E0;
|
||||
border-bottom: 1px none #E0E0E0;
|
||||
border-left: 1px none #E0E0E0;
|
||||
margin: 0px;
|
||||
}
|
||||
.mdescRight {
|
||||
padding: 0px 8px 4px 8px;
|
||||
font-size: 80%;
|
||||
font-style: italic;
|
||||
background-color: #FAFAFA;
|
||||
border-top: 1px none #E0E0E0;
|
||||
border-right: 1px none #E0E0E0;
|
||||
border-bottom: 1px none #E0E0E0;
|
||||
border-left: 1px none #E0E0E0;
|
||||
margin: 0px;
|
||||
}
|
||||
.memItemLeft {
|
||||
padding: 1px 0px 0px 8px;
|
||||
margin: 4px;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-color: #E0E0E0;
|
||||
border-right-color: #E0E0E0;
|
||||
border-bottom-color: #E0E0E0;
|
||||
border-left-color: #E0E0E0;
|
||||
border-top-style: solid;
|
||||
border-right-style: none;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
background-color: #FAFAFA;
|
||||
font-size: 80%;
|
||||
}
|
||||
.memItemRight {
|
||||
padding: 1px 8px 0px 8px;
|
||||
margin: 4px;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-color: #E0E0E0;
|
||||
border-right-color: #E0E0E0;
|
||||
border-bottom-color: #E0E0E0;
|
||||
border-left-color: #E0E0E0;
|
||||
border-top-style: solid;
|
||||
border-right-style: none;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
background-color: #FAFAFA;
|
||||
font-size: 80%;
|
||||
}
|
||||
.memTemplItemLeft {
|
||||
padding: 1px 0px 0px 8px;
|
||||
margin: 4px;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-color: #E0E0E0;
|
||||
border-right-color: #E0E0E0;
|
||||
border-bottom-color: #E0E0E0;
|
||||
border-left-color: #E0E0E0;
|
||||
border-top-style: none;
|
||||
border-right-style: none;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
background-color: #FAFAFA;
|
||||
font-size: 80%;
|
||||
}
|
||||
.memTemplItemRight {
|
||||
padding: 1px 8px 0px 8px;
|
||||
margin: 4px;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-color: #E0E0E0;
|
||||
border-right-color: #E0E0E0;
|
||||
border-bottom-color: #E0E0E0;
|
||||
border-left-color: #E0E0E0;
|
||||
border-top-style: none;
|
||||
border-right-style: none;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
background-color: #FAFAFA;
|
||||
font-size: 80%;
|
||||
}
|
||||
.memTemplParams {
|
||||
padding: 1px 0px 0px 8px;
|
||||
margin: 4px;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-color: #E0E0E0;
|
||||
border-right-color: #E0E0E0;
|
||||
border-bottom-color: #E0E0E0;
|
||||
border-left-color: #E0E0E0;
|
||||
border-top-style: solid;
|
||||
border-right-style: none;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
color: #606060;
|
||||
background-color: #FAFAFA;
|
||||
font-size: 80%;
|
||||
}
|
||||
.search { color: #003399;
|
||||
font-weight: bold;
|
||||
}
|
||||
FORM.search {
|
||||
margin-bottom: 0px;
|
||||
margin-top: 0px;
|
||||
}
|
||||
INPUT.search { font-size: 75%;
|
||||
color: #000080;
|
||||
font-weight: normal;
|
||||
background-color: #e8eef2;
|
||||
}
|
||||
TD.tiny { font-size: 75%;
|
||||
}
|
||||
a {
|
||||
color: #1A41A8;
|
||||
}
|
||||
a:visited {
|
||||
color: #2A3798;
|
||||
}
|
||||
.dirtab { padding: 4px;
|
||||
border-collapse: collapse;
|
||||
border: 1px solid #84b0c7;
|
||||
}
|
||||
TH.dirtab { background: #e8eef2;
|
||||
font-weight: bold;
|
||||
}
|
||||
HR { height: 1px;
|
||||
border: none;
|
||||
border-top: 1px solid black;
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 174 B |
|
After Width: | Height: | Size: 255 B |
|
After Width: | Height: | Size: 259 B |
|
After Width: | Height: | Size: 261 B |
|
After Width: | Height: | Size: 233 B |
|
After Width: | Height: | Size: 358 B |
|
After Width: | Height: | Size: 160 B |
|
After Width: | Height: | Size: 194 B |
|
After Width: | Height: | Size: 235 B |
|
After Width: | Height: | Size: 165 B |
|
After Width: | Height: | Size: 200 B |
|
After Width: | Height: | Size: 229 B |
@@ -0,0 +1,43 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
|
||||
<HTML><HEAD></HEAD><BODY>
|
||||
<OBJECT type="text/site properties">
|
||||
<param name="FrameName" value="right">
|
||||
</OBJECT>
|
||||
<UL>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Name" value="The Protothreads Library"><param name="Local" value="main.html"><param name="ImageNumber" value="11"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Name" value="File List"><param name="Local" value="files.html"><param name="ImageNumber" value="1"></OBJECT>
|
||||
<UL>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Name" value="lc-addrlabels.h"><param name="Local" value="a00009.html"><param name="ImageNumber" value="11"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Name" value="lc-switch.h"><param name="Local" value="a00010.html"><param name="ImageNumber" value="11"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Name" value="lc.h"><param name="Local" value="a00011.html"><param name="ImageNumber" value="11"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Name" value="pt-sem.h"><param name="Local" value="a00012.html"><param name="ImageNumber" value="11"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Name" value="pt.h"><param name="Local" value="a00013.html"><param name="ImageNumber" value="11"></OBJECT>
|
||||
</UL>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Name" value="Data Structures"><param name="Local" value="annotated.html"><param name="ImageNumber" value="1"></OBJECT>
|
||||
<UL>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Name" value="pt"><param name="Local" value="a00005.html"><param name="ImageNumber" value="11"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Name" value="pt_sem"><param name="Local" value="a00006.html"><param name="ImageNumber" value="11"></OBJECT>
|
||||
</UL>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Name" value="Class Hierarchy"><param name="Local" value="hierarchy.html"><param name="ImageNumber" value="1"></OBJECT>
|
||||
<UL>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Name" value="pt"><param name="Local" value="a00005.html"><param name="ImageNumber" value="11"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Name" value="pt_sem"><param name="Local" value="a00006.html"><param name="ImageNumber" value="11"></OBJECT>
|
||||
</UL>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Name" value="Data Fields"><param name="Local" value="functions.html"><param name="ImageNumber" value="11"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Name" value="Modules"><param name="Local" value="modules.html"><param name="ImageNumber" value="1"></OBJECT>
|
||||
<UL>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Name" value="Protothreads"><param name="Local" value="a00014.html"><param name="ImageNumber" value="1"></OBJECT>
|
||||
<UL>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Name" value="Protothread semaphores"><param name="Local" value="a00016.html"><param name="ImageNumber" value="11"></OBJECT>
|
||||
<UL>
|
||||
</UL>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Name" value="Local continuations"><param name="Local" value="a00017.html"><param name="ImageNumber" value="11"></OBJECT>
|
||||
<UL>
|
||||
</UL>
|
||||
</UL>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Name" value="Examples"><param name="Local" value="a00015.html"><param name="ImageNumber" value="11"></OBJECT>
|
||||
<UL>
|
||||
</UL>
|
||||
</UL>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Name" value="Globals"><param name="Local" value="globals.html"><param name="ImageNumber" value="11"></OBJECT>
|
||||
</UL>
|
||||
@@ -0,0 +1,56 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
|
||||
<HTML><HEAD></HEAD><BODY>
|
||||
<OBJECT type="text/site properties">
|
||||
<param name="FrameName" value="right">
|
||||
</OBJECT>
|
||||
<UL>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00017.html#g3d76802e55349cc8bf74f286ced203c3"><param name="Name" value="LC_END"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00017.html#g9ca9d0fef02b9c5d93bed2834e7aeb76"><param name="Name" value="LC_INIT"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00017.html#g33dad6011c98dfeb4e64fee1d6892cb3"><param name="Name" value="LC_RESUME"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00017.html#gfb1d5e671e40464a7a7bda589b5d4341"><param name="Name" value="LC_SET"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00017.html"><param name="Name" value="Local continuations"></OBJECT>
|
||||
<UL>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00017.html#g3d76802e55349cc8bf74f286ced203c3"><param name="Name" value="LC_END"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00017.html#g9ca9d0fef02b9c5d93bed2834e7aeb76"><param name="Name" value="LC_INIT"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00017.html#g33dad6011c98dfeb4e64fee1d6892cb3"><param name="Name" value="LC_RESUME"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00017.html#gfb1d5e671e40464a7a7bda589b5d4341"><param name="Name" value="LC_SET"></OBJECT>
|
||||
</UL>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00016.html"><param name="Name" value="Protothread semaphores"></OBJECT>
|
||||
<UL>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00016.html#gd7089c5dc86f12019f0361d82a75b04b"><param name="Name" value="PT_SEM_INIT"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00016.html#g1eaaf4d9d75e24582acc6440d7085f19"><param name="Name" value="PT_SEM_SIGNAL"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00016.html#g386ff87a52a840512906f2940e229e2e"><param name="Name" value="PT_SEM_WAIT"></OBJECT>
|
||||
</UL>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00014.html"><param name="Name" value="Protothreads"></OBJECT>
|
||||
<UL>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00014.html#g2ffbb9e554e08a343ae2f9de4bedfdfc"><param name="Name" value="PT_BEGIN"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00014.html#g7b04a0035bef29d905496c23bae066d2"><param name="Name" value="PT_END"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00014.html#g905451249dca72ce0385bf2a9ff178ee"><param name="Name" value="PT_EXIT"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00014.html#ge6bae7dc0225468c8a5ac269df549892"><param name="Name" value="PT_INIT"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00014.html#gcd3ac045f0a4ae63412e3b3d8780e8ab"><param name="Name" value="PT_RESTART"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00014.html#gfa82b860a64b67d25ab3abc21811896f"><param name="Name" value="PT_SCHEDULE"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00014.html#g9e97a0b4d5cc7764d8e19758f5da53ae"><param name="Name" value="PT_SPAWN"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00014.html#g3d4c8bd4aada659eb34f5d2ffd3e7901"><param name="Name" value="PT_THREAD"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00014.html#g2f8f70c30b9ee08a103fbd69a4365c4c"><param name="Name" value="PT_WAIT_THREAD"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00014.html#g99e43010ec61327164466aa2d902de45"><param name="Name" value="PT_WAIT_UNTIL"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00014.html#gad14bbbf092b90aa0a5a4f9169504a8d"><param name="Name" value="PT_WAIT_WHILE"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00014.html#g155cba6121323726d02c00284428fed6"><param name="Name" value="PT_YIELD"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00014.html#ge3c821e3a388615528efda9d23c7d115"><param name="Name" value="PT_YIELD_UNTIL"></OBJECT>
|
||||
</UL>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00014.html#g2ffbb9e554e08a343ae2f9de4bedfdfc"><param name="Name" value="PT_BEGIN"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00014.html#g7b04a0035bef29d905496c23bae066d2"><param name="Name" value="PT_END"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00014.html#g905451249dca72ce0385bf2a9ff178ee"><param name="Name" value="PT_EXIT"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00014.html#ge6bae7dc0225468c8a5ac269df549892"><param name="Name" value="PT_INIT"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00014.html#gcd3ac045f0a4ae63412e3b3d8780e8ab"><param name="Name" value="PT_RESTART"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00014.html#gfa82b860a64b67d25ab3abc21811896f"><param name="Name" value="PT_SCHEDULE"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00016.html#gd7089c5dc86f12019f0361d82a75b04b"><param name="Name" value="PT_SEM_INIT"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00016.html#g1eaaf4d9d75e24582acc6440d7085f19"><param name="Name" value="PT_SEM_SIGNAL"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00016.html#g386ff87a52a840512906f2940e229e2e"><param name="Name" value="PT_SEM_WAIT"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00014.html#g9e97a0b4d5cc7764d8e19758f5da53ae"><param name="Name" value="PT_SPAWN"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00014.html#g3d4c8bd4aada659eb34f5d2ffd3e7901"><param name="Name" value="PT_THREAD"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00014.html#g2f8f70c30b9ee08a103fbd69a4365c4c"><param name="Name" value="PT_WAIT_THREAD"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00014.html#g99e43010ec61327164466aa2d902de45"><param name="Name" value="PT_WAIT_UNTIL"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00014.html#gad14bbbf092b90aa0a5a4f9169504a8d"><param name="Name" value="PT_WAIT_WHILE"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00014.html#g155cba6121323726d02c00284428fed6"><param name="Name" value="PT_YIELD"></OBJECT>
|
||||
<LI><OBJECT type="text/sitemap"><param name="Local" value="a00014.html#ge3c821e3a388615528efda9d23c7d115"><param name="Name" value="PT_YIELD_UNTIL"></OBJECT>
|
||||
</UL>
|
||||
@@ -0,0 +1,44 @@
|
||||
[OPTIONS]
|
||||
Compatibility=1.1
|
||||
Full-text search=Yes
|
||||
Contents file=index.hhc
|
||||
Default Window=main
|
||||
Default topic=main.html
|
||||
Index file=index.hhk
|
||||
Language=0x409 English (United States)
|
||||
Title=The Protothreads Library 1.4
|
||||
|
||||
[WINDOWS]
|
||||
main="The Protothreads Library 1.4","index.hhc","index.hhk","main.html","main.html",,,,,0x23520,,0x387e,,,,,,,,0
|
||||
|
||||
[FILES]
|
||||
main.html
|
||||
files.html
|
||||
a00018.html
|
||||
a00019.html
|
||||
a00020.html
|
||||
a00021.html
|
||||
a00022.html
|
||||
a00009.html
|
||||
a00010.html
|
||||
a00011.html
|
||||
a00012.html
|
||||
a00013.html
|
||||
annotated.html
|
||||
hierarchy.html
|
||||
functions.html
|
||||
functions_vars.html
|
||||
a00005.html
|
||||
a00006.html
|
||||
a00014.html
|
||||
a00015.html
|
||||
a00016.html
|
||||
a00017.html
|
||||
modules.html
|
||||
globals.html
|
||||
globals_type.html
|
||||
globals_defs.html
|
||||
tabs.css
|
||||
tab_b.gif
|
||||
tab_l.gif
|
||||
tab_r.gif
|
||||
|
After Width: | Height: | Size: 35 B |
|
After Width: | Height: | Size: 706 B |
|
After Width: | Height: | Size: 2.5 KiB |
@@ -0,0 +1,102 @@
|
||||
/* tabs styles, based on http://www.alistapart.com/articles/slidingdoors */
|
||||
|
||||
DIV.tabs
|
||||
{
|
||||
float : left;
|
||||
width : 100%;
|
||||
background : url("tab_b.gif") repeat-x bottom;
|
||||
margin-bottom : 4px;
|
||||
}
|
||||
|
||||
DIV.tabs UL
|
||||
{
|
||||
margin : 0px;
|
||||
padding-left : 10px;
|
||||
list-style : none;
|
||||
}
|
||||
|
||||
DIV.tabs LI, DIV.tabs FORM
|
||||
{
|
||||
display : inline;
|
||||
margin : 0px;
|
||||
padding : 0px;
|
||||
}
|
||||
|
||||
DIV.tabs FORM
|
||||
{
|
||||
float : right;
|
||||
}
|
||||
|
||||
DIV.tabs A
|
||||
{
|
||||
float : left;
|
||||
background : url("tab_r.gif") no-repeat right top;
|
||||
border-bottom : 1px solid #84B0C7;
|
||||
font-size : x-small;
|
||||
font-weight : bold;
|
||||
text-decoration : none;
|
||||
}
|
||||
|
||||
DIV.tabs A:hover
|
||||
{
|
||||
background-position: 100% -150px;
|
||||
}
|
||||
|
||||
DIV.tabs A:link, DIV.tabs A:visited,
|
||||
DIV.tabs A:active, DIV.tabs A:hover
|
||||
{
|
||||
color: #1A419D;
|
||||
}
|
||||
|
||||
DIV.tabs SPAN
|
||||
{
|
||||
float : left;
|
||||
display : block;
|
||||
background : url("tab_l.gif") no-repeat left top;
|
||||
padding : 5px 9px;
|
||||
white-space : nowrap;
|
||||
}
|
||||
|
||||
DIV.tabs INPUT
|
||||
{
|
||||
float : right;
|
||||
display : inline;
|
||||
font-size : 1em;
|
||||
}
|
||||
|
||||
DIV.tabs TD
|
||||
{
|
||||
font-size : x-small;
|
||||
font-weight : bold;
|
||||
text-decoration : none;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Commented Backslash Hack hides rule from IE5-Mac \*/
|
||||
DIV.tabs SPAN {float : none;}
|
||||
/* End IE5-Mac hack */
|
||||
|
||||
DIV.tabs A:hover SPAN
|
||||
{
|
||||
background-position: 0% -150px;
|
||||
}
|
||||
|
||||
DIV.tabs LI#current A
|
||||
{
|
||||
background-position: 100% -150px;
|
||||
border-width : 0px;
|
||||
}
|
||||
|
||||
DIV.tabs LI#current SPAN
|
||||
{
|
||||
background-position: 0% -150px;
|
||||
padding-bottom : 6px;
|
||||
}
|
||||
|
||||
DIV.nav
|
||||
{
|
||||
background : none;
|
||||
border : none;
|
||||
border-bottom : 1px solid #84B0C7;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
\defgroup pt Protothreads
|
||||
@{
|
||||
Protothreads are implemented in a single header file, pt.h, which
|
||||
includes the local continuations header file, lc.h. This file in turn
|
||||
includes the actual implementation of local continuations, which
|
||||
typically also is contained in a single header file.
|
||||
|
||||
*/
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
\defgroup examples Examples
|
||||
@{
|
||||
|
||||
\section example-small A small example
|
||||
|
||||
This first example shows a very simple program: two protothreads
|
||||
waiting for each other to toggle two flags. The code illustrates how
|
||||
to write protothreads code, how to initialize protothreads, and how to
|
||||
schedule them.
|
||||
|
||||
\include example-small.c
|
||||
|
||||
|
||||
\section example-code-lock A code-lock
|
||||
This example shows how to implement a simple code lock - the kind of
|
||||
device that is placed next to doors and that you have to push a four
|
||||
digit number into in order to unlock the door.
|
||||
|
||||
The code lock waits for key presses from a numeric keyboard and if the
|
||||
correct code is entered, the lock is unlocked. There is a maximum time
|
||||
of one second between each key press, and after the correct code has
|
||||
been entered, no more keys must be pressed for 0.5 seconds before the
|
||||
lock is opened.
|
||||
|
||||
\include example-codelock.c
|
||||
|
||||
\section example-buffer The bounded buffer with protothread semaphores
|
||||
|
||||
The following example shows how to implement the bounded buffer
|
||||
problem using the protothreads semaphore library. The example uses
|
||||
three protothreads: one producer() protothread that produces items,
|
||||
one consumer() protothread that consumes items, and one
|
||||
driver_thread() that schedules the producer and consumer protothreads.
|
||||
|
||||
Note that there is no need for a mutex to guard the add_to_buffer()
|
||||
and get_from_buffer() functions because of the implicit locking
|
||||
semantics of protothreads - a protothread will never be preempted and
|
||||
will never block except in an explicit PT_WAIT statement.
|
||||
|
||||
\include example-buffer.c
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,156 @@
|
||||
/**
|
||||
|
||||
\mainpage The Protothreads Library
|
||||
|
||||
\author Adam Dunkels <adam@sics.se>
|
||||
|
||||
Protothreads are a type of lightweight stackless threads designed for
|
||||
severly memory constrained systems such as deeply embedded systems or
|
||||
sensor network nodes. Protothreads provides linear code execution for
|
||||
event-driven systems implemented in C. Protothreads can be used with
|
||||
or without an RTOS.
|
||||
|
||||
Protothreads are a extremely lightweight, stackless type of threads
|
||||
that provides a blocking context on top of an event-driven system,
|
||||
without the overhead of per-thread stacks. The purpose of protothreads
|
||||
is to implement sequential flow of control without complex state
|
||||
machines or full multi-threading. Protothreads provides conditional
|
||||
blocking inside C functions.
|
||||
|
||||
Main features:
|
||||
|
||||
- No machine specific code - the protothreads library is pure C
|
||||
|
||||
- Does not use error-prone functions such as longjmp()
|
||||
|
||||
- Very small RAM overhead - only two bytes per protothread
|
||||
|
||||
- Can be used with or without an OS
|
||||
|
||||
- Provides blocking wait without full multi-threading or
|
||||
stack-switching
|
||||
|
||||
Examples applications:
|
||||
|
||||
- Memory constrained systems
|
||||
|
||||
- Event-driven protocol stacks
|
||||
|
||||
- Deeply embedded systems
|
||||
|
||||
- Sensor network nodes
|
||||
|
||||
|
||||
\sa \ref examples "Example programs"
|
||||
\sa \ref pt "Protothreads API documentation"
|
||||
|
||||
The protothreads library is released under a BSD-style license that
|
||||
allows for both non-commercial and commercial usage. The only
|
||||
requirement is that credit is given.
|
||||
|
||||
More information and new version of the code can be found at the
|
||||
Protothreads homepage:
|
||||
|
||||
http://www.sics.se/~adam/pt/
|
||||
|
||||
\section authors Authors
|
||||
|
||||
The protothreads library was written by Adam Dunkels <adam@sics.se>
|
||||
with support from Oliver Schmidt <ol.sc@web.de>.
|
||||
|
||||
\section using Using protothreads
|
||||
|
||||
Using protothreads in a project is easy: simply copy the files pt.h,
|
||||
lc.h and lc-switch.h into the include files directory of the project,
|
||||
and \#include "pt.h" in all files that should use protothreads.
|
||||
|
||||
\section pt-desc Protothreads
|
||||
|
||||
Protothreads are a extremely lightweight, stackless threads that
|
||||
provides a blocking context on top of an event-driven system, without
|
||||
the overhead of per-thread stacks. The purpose of protothreads is to
|
||||
implement sequential flow of control without using complex state
|
||||
machines or full multi-threading. Protothreads provides conditional
|
||||
blocking inside a C function.
|
||||
|
||||
In memory constrained systems, such as deeply embedded systems,
|
||||
traditional multi-threading may have a too large memory overhead. In
|
||||
traditional multi-threading, each thread requires its own stack, that
|
||||
typically is over-provisioned. The stacks may use large parts of the
|
||||
available memory.
|
||||
|
||||
The main advantage of protothreads over ordinary threads is that
|
||||
protothreads are very lightweight: a protothread does not require its
|
||||
own stack. Rather, all protothreads run on the same stack and context
|
||||
switching is done by stack rewinding. This is advantageous in memory
|
||||
constrained systems, where a stack for a thread might use a large part
|
||||
of the available memory. A protothread only requires only two bytes of
|
||||
memory per protothread. Moreover, protothreads are implemented in pure
|
||||
C and do not require any machine-specific assembler code.
|
||||
|
||||
A protothread runs within a single C function and cannot span over
|
||||
other functions. A protothread may call normal C functions, but cannot
|
||||
block inside a called function. Blocking inside nested function calls
|
||||
is instead made by spawning a separate protothread for each
|
||||
potentially blocking function. The advantage of this approach is that
|
||||
blocking is explicit: the programmer knows exactly which functions
|
||||
that block that which functions the never blocks.
|
||||
|
||||
Protothreads are similar to asymmetric co-routines. The main
|
||||
difference is that co-routines uses a separate stack for each
|
||||
co-routine, whereas protothreads are stackless. The most similar
|
||||
mechanism to protothreads are Python generators. These are also
|
||||
stackless constructs, but have a different purpose. Protothreads
|
||||
provides blocking contexts inside a C function, whereas Python
|
||||
generators provide multiple exit points from a generator function.
|
||||
|
||||
\section pt-autovars Local variables
|
||||
|
||||
\note
|
||||
Because protothreads do not save the stack context across a blocking
|
||||
call, local variables are not preserved when the protothread
|
||||
blocks. This means that local variables should be used with utmost
|
||||
care - if in doubt, do not use local variables inside a protothread!
|
||||
|
||||
\section pt-scheduling Scheduling
|
||||
|
||||
A protothread is driven by repeated calls to the function in which the
|
||||
protothread is running. Each time the function is called, the
|
||||
protothread will run until it blocks or exits. Thus the scheduling of
|
||||
protothreads is done by the application that uses protothreads.
|
||||
|
||||
\section pt-impl Implementation
|
||||
|
||||
Protothreads are implemented using local continuations. A local
|
||||
continuation represents the current state of execution at a particular
|
||||
place in the program, but does not provide any call history or local
|
||||
variables. A local continuation can be set in a specific function to
|
||||
capture the state of the function. After a local continuation has been
|
||||
set can be resumed in order to restore the state of the function at
|
||||
the point where the local continuation was set.
|
||||
|
||||
|
||||
Local continuations can be implemented in a variety of ways:
|
||||
|
||||
-# by using machine specific assembler code,
|
||||
-# by using standard C constructs, or
|
||||
-# by using compiler extensions.
|
||||
|
||||
The first way works by saving and restoring the processor state,
|
||||
except for stack pointers, and requires between 16 and 32 bytes of
|
||||
memory per protothread. The exact amount of memory required depends on
|
||||
the architecture.
|
||||
|
||||
The standard C implementation requires only two bytes of state per
|
||||
protothread and utilizes the C switch() statement in a non-obvious way
|
||||
that is similar to Duff's device. This implementation does, however,
|
||||
impose a slight restriction to the code that uses protothreads: a
|
||||
protothread cannot perform a blocking wait (PT_WAIT_UNTIL() or
|
||||
PT_YIELD()) inside a switch() statement.
|
||||
|
||||
Certain compilers has C extensions that can be used to implement
|
||||
protothreads. GCC supports label pointers that can be used for this
|
||||
purpose. With this implementation, protothreads require 4 bytes of RAM
|
||||
per protothread.
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2005, Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the protothreads library.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
* $Id: example-buffer.c,v 1.5 2005/10/07 05:21:33 adam Exp $
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
|
||||
#include "pt-sem.h"
|
||||
|
||||
#define NUM_ITEMS 32
|
||||
#define BUFSIZE 8
|
||||
|
||||
static int buffer[BUFSIZE];
|
||||
static int bufptr;
|
||||
|
||||
static void
|
||||
add_to_buffer(int item)
|
||||
{
|
||||
printf("Item %d added to buffer at place %d\n", item, bufptr);
|
||||
buffer[bufptr] = item;
|
||||
bufptr = (bufptr + 1) % BUFSIZE;
|
||||
}
|
||||
static int
|
||||
get_from_buffer(void)
|
||||
{
|
||||
int item;
|
||||
item = buffer[bufptr];
|
||||
printf("Item %d retrieved from buffer at place %d\n",
|
||||
item, bufptr);
|
||||
bufptr = (bufptr + 1) % BUFSIZE;
|
||||
return item;
|
||||
}
|
||||
|
||||
static int
|
||||
produce_item(void)
|
||||
{
|
||||
static int item = 0;
|
||||
printf("Item %d produced\n", item);
|
||||
return item++;
|
||||
}
|
||||
|
||||
static void
|
||||
consume_item(int item)
|
||||
{
|
||||
printf("Item %d consumed\n", item);
|
||||
}
|
||||
|
||||
static struct pt_sem full, empty;
|
||||
|
||||
static
|
||||
PT_THREAD(producer(struct pt *pt))
|
||||
{
|
||||
static int produced;
|
||||
|
||||
PT_BEGIN(pt);
|
||||
|
||||
for(produced = 0; produced < NUM_ITEMS; ++produced) {
|
||||
|
||||
PT_SEM_WAIT(pt, &full);
|
||||
|
||||
add_to_buffer(produce_item());
|
||||
|
||||
PT_SEM_SIGNAL(pt, &empty);
|
||||
}
|
||||
|
||||
PT_END(pt);
|
||||
}
|
||||
|
||||
static
|
||||
PT_THREAD(consumer(struct pt *pt))
|
||||
{
|
||||
static int consumed;
|
||||
|
||||
PT_BEGIN(pt);
|
||||
|
||||
for(consumed = 0; consumed < NUM_ITEMS; ++consumed) {
|
||||
|
||||
PT_SEM_WAIT(pt, &empty);
|
||||
|
||||
consume_item(get_from_buffer());
|
||||
|
||||
PT_SEM_SIGNAL(pt, &full);
|
||||
}
|
||||
|
||||
PT_END(pt);
|
||||
}
|
||||
|
||||
static
|
||||
PT_THREAD(driver_thread(struct pt *pt))
|
||||
{
|
||||
static struct pt pt_producer, pt_consumer;
|
||||
|
||||
PT_BEGIN(pt);
|
||||
|
||||
PT_SEM_INIT(&empty, 0);
|
||||
PT_SEM_INIT(&full, BUFSIZE);
|
||||
|
||||
PT_INIT(&pt_producer);
|
||||
PT_INIT(&pt_consumer);
|
||||
|
||||
PT_WAIT_THREAD(pt, producer(&pt_producer) &
|
||||
consumer(&pt_consumer));
|
||||
|
||||
PT_END(pt);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
struct pt driver_pt;
|
||||
|
||||
PT_INIT(&driver_pt);
|
||||
|
||||
while(PT_SCHEDULE(driver_thread(&driver_pt))) {
|
||||
|
||||
/*
|
||||
* When running this example on a multitasking system, we must
|
||||
* give other processes a chance to run too and therefore we call
|
||||
* usleep() resp. Sleep() here. On a dedicated embedded system,
|
||||
* we usually do not need to do this.
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
Sleep(0);
|
||||
#else
|
||||
usleep(10);
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,414 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2005, Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the protothreads library.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
* $Id: example-codelock.c,v 1.5 2005/10/06 07:57:08 adam Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* This example shows how to implement a simple code lock. The code
|
||||
* lock waits for key presses from a numeric keyboard and if the
|
||||
* correct code is entered, the lock is unlocked. There is a maximum
|
||||
* time of one second between each key press, and after the correct
|
||||
* code has been entered, no more keys must be pressed for 0.5 seconds
|
||||
* before the lock is opened.
|
||||
*
|
||||
* This is an example that shows two things:
|
||||
* - how to implement a code lock key input mechanism, and
|
||||
* - how to implement a sequential timed routine.
|
||||
*
|
||||
* The program consists of two protothreads, one that implements the
|
||||
* code lock reader and one that implements simulated keyboard input.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
|
||||
#include "pt.h"
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/*
|
||||
* The following definitions are just for the simple timer library
|
||||
* used in this example. The actual implementation of the functions
|
||||
* can be found at the end of this file.
|
||||
*/
|
||||
struct timer { int start, interval; };
|
||||
static int timer_expired(struct timer *t);
|
||||
static void timer_set(struct timer *t, int usecs);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/*
|
||||
* This example uses two timers: one for the code lock protothread and
|
||||
* one for the simulated key input protothread.
|
||||
*/
|
||||
static struct timer codelock_timer, input_timer;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/*
|
||||
* This is the code that has to be entered.
|
||||
*/
|
||||
static const char code[4] = {'1', '4', '2', '3'};
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/*
|
||||
* This example has two protothread and therefor has two protothread
|
||||
* control structures of type struct pt. These are initialized with
|
||||
* PT_INIT() in the main() function below.
|
||||
*/
|
||||
static struct pt codelock_pt, input_pt;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/*
|
||||
* The following code implements a simple key input. Input is made
|
||||
* with the press_key() function, and the function key_pressed()
|
||||
* checks if a key has been pressed. The variable "key" holds the
|
||||
* latest key that was pressed. The variable "key_pressed_flag" is set
|
||||
* when a key is pressed and cleared when a key press is checked.
|
||||
*/
|
||||
static char key, key_pressed_flag;
|
||||
|
||||
static void
|
||||
press_key(char k)
|
||||
{
|
||||
printf("--- Key '%c' pressed\n", k);
|
||||
key = k;
|
||||
key_pressed_flag = 1;
|
||||
}
|
||||
|
||||
static int
|
||||
key_pressed(void)
|
||||
{
|
||||
if(key_pressed_flag != 0) {
|
||||
key_pressed_flag = 0;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/*
|
||||
* Declaration of the protothread function implementing the code lock
|
||||
* logic. The protothread function is declared using the PT_THREAD()
|
||||
* macro. The function is declared with the "static" keyword since it
|
||||
* is local to this file. The name of the function is codelock_thread
|
||||
* and it takes one argument, pt, of the type struct pt.
|
||||
*
|
||||
*/
|
||||
static
|
||||
PT_THREAD(codelock_thread(struct pt *pt))
|
||||
{
|
||||
/* This is a local variable that holds the number of keys that have
|
||||
* been pressed. Note that it is declared with the "static" keyword
|
||||
* to make sure that the variable is *not* allocated on the stack.
|
||||
*/
|
||||
static int keys;
|
||||
|
||||
/*
|
||||
* Declare the beginning of the protothread.
|
||||
*/
|
||||
PT_BEGIN(pt);
|
||||
|
||||
/*
|
||||
* We'll let the protothread loop until the protothread is
|
||||
* expliticly exited with PT_EXIT().
|
||||
*/
|
||||
while(1) {
|
||||
|
||||
/*
|
||||
* We'll be reading key presses until we get the right amount of
|
||||
* correct keys.
|
||||
*/
|
||||
for(keys = 0; keys < sizeof(code); ++keys) {
|
||||
|
||||
/*
|
||||
* If we haven't gotten any keypresses, we'll simply wait for one.
|
||||
*/
|
||||
if(keys == 0) {
|
||||
|
||||
/*
|
||||
* The PT_WAIT_UNTIL() function will block until the condition
|
||||
* key_pressed() is true.
|
||||
*/
|
||||
PT_WAIT_UNTIL(pt, key_pressed());
|
||||
} else {
|
||||
|
||||
/*
|
||||
* If the "key" variable was larger than zero, we have already
|
||||
* gotten at least one correct key press. If so, we'll not
|
||||
* only wait for the next key, but we'll also set a timer that
|
||||
* expires in one second. This gives the person pressing the
|
||||
* keys one second to press the next key in the code.
|
||||
*/
|
||||
timer_set(&codelock_timer, 1000);
|
||||
|
||||
/*
|
||||
* The following statement shows how complex blocking
|
||||
* conditions can be easily expressed with protothreads and
|
||||
* the PT_WAIT_UNTIL() function.
|
||||
*/
|
||||
PT_WAIT_UNTIL(pt, key_pressed() || timer_expired(&codelock_timer));
|
||||
|
||||
/*
|
||||
* If the timer expired, we should break out of the for() loop
|
||||
* and start reading keys from the beginning of the while(1)
|
||||
* loop instead.
|
||||
*/
|
||||
if(timer_expired(&codelock_timer)) {
|
||||
printf("Code lock timer expired.\n");
|
||||
|
||||
/*
|
||||
* Break out from the for() loop and start from the
|
||||
* beginning of the while(1) loop.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the pressed key was correct.
|
||||
*/
|
||||
if(key != code[keys]) {
|
||||
printf("Incorrect key '%c' found\n", key);
|
||||
/*
|
||||
* Break out of the for() loop since the key was incorrect.
|
||||
*/
|
||||
break;
|
||||
} else {
|
||||
printf("Correct key '%c' found\n", key);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if we have gotten all keys.
|
||||
*/
|
||||
if(keys == sizeof(code)) {
|
||||
printf("Correct code entered, waiting for 500 ms before unlocking.\n");
|
||||
|
||||
/*
|
||||
* Ok, we got the correct code. But to make sure that the code
|
||||
* was not just a fluke of luck by an intruder, but the correct
|
||||
* code entered by a person that knows the correct code, we'll
|
||||
* wait for half a second before opening the lock. If another
|
||||
* key is pressed during this time, we'll assume that it was a
|
||||
* fluke of luck that the correct code was entered the first
|
||||
* time.
|
||||
*/
|
||||
timer_set(&codelock_timer, 500);
|
||||
PT_WAIT_UNTIL(pt, key_pressed() || timer_expired(&codelock_timer));
|
||||
|
||||
/*
|
||||
* If we continued from the PT_WAIT_UNTIL() statement without
|
||||
* the timer expired, we don't open the lock.
|
||||
*/
|
||||
if(!timer_expired(&codelock_timer)) {
|
||||
printf("Key pressed during final wait, code lock locked again.\n");
|
||||
} else {
|
||||
|
||||
/*
|
||||
* If the timer expired, we'll open the lock and exit from the
|
||||
* protothread.
|
||||
*/
|
||||
printf("Code lock unlocked.\n");
|
||||
PT_EXIT(pt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Finally, we'll mark the end of the protothread.
|
||||
*/
|
||||
PT_END(pt);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/*
|
||||
* This is the second protothread in this example. It implements a
|
||||
* simulated user pressing the keys. This illustrates how a linear
|
||||
* sequence of timed instructions can be implemented with
|
||||
* protothreads.
|
||||
*/
|
||||
static
|
||||
PT_THREAD(input_thread(struct pt *pt))
|
||||
{
|
||||
PT_BEGIN(pt);
|
||||
|
||||
printf("Waiting 1 second before entering first key.\n");
|
||||
|
||||
timer_set(&input_timer, 1000);
|
||||
PT_WAIT_UNTIL(pt, timer_expired(&input_timer));
|
||||
|
||||
press_key('1');
|
||||
|
||||
timer_set(&input_timer, 100);
|
||||
PT_WAIT_UNTIL(pt, timer_expired(&input_timer));
|
||||
|
||||
press_key('2');
|
||||
|
||||
timer_set(&input_timer, 100);
|
||||
PT_WAIT_UNTIL(pt, timer_expired(&input_timer));
|
||||
|
||||
press_key('3');
|
||||
|
||||
timer_set(&input_timer, 2000);
|
||||
PT_WAIT_UNTIL(pt, timer_expired(&input_timer));
|
||||
|
||||
press_key('1');
|
||||
|
||||
timer_set(&input_timer, 200);
|
||||
PT_WAIT_UNTIL(pt, timer_expired(&input_timer));
|
||||
|
||||
press_key('4');
|
||||
|
||||
timer_set(&input_timer, 200);
|
||||
PT_WAIT_UNTIL(pt, timer_expired(&input_timer));
|
||||
|
||||
press_key('2');
|
||||
|
||||
timer_set(&input_timer, 2000);
|
||||
PT_WAIT_UNTIL(pt, timer_expired(&input_timer));
|
||||
|
||||
press_key('3');
|
||||
|
||||
timer_set(&input_timer, 200);
|
||||
PT_WAIT_UNTIL(pt, timer_expired(&input_timer));
|
||||
|
||||
press_key('1');
|
||||
|
||||
timer_set(&input_timer, 200);
|
||||
PT_WAIT_UNTIL(pt, timer_expired(&input_timer));
|
||||
|
||||
press_key('4');
|
||||
|
||||
timer_set(&input_timer, 200);
|
||||
PT_WAIT_UNTIL(pt, timer_expired(&input_timer));
|
||||
|
||||
press_key('2');
|
||||
|
||||
timer_set(&input_timer, 100);
|
||||
PT_WAIT_UNTIL(pt, timer_expired(&input_timer));
|
||||
|
||||
press_key('3');
|
||||
|
||||
timer_set(&input_timer, 100);
|
||||
PT_WAIT_UNTIL(pt, timer_expired(&input_timer));
|
||||
|
||||
press_key('4');
|
||||
|
||||
timer_set(&input_timer, 1500);
|
||||
PT_WAIT_UNTIL(pt, timer_expired(&input_timer));
|
||||
|
||||
press_key('1');
|
||||
|
||||
timer_set(&input_timer, 300);
|
||||
PT_WAIT_UNTIL(pt, timer_expired(&input_timer));
|
||||
|
||||
press_key('4');
|
||||
|
||||
timer_set(&input_timer, 400);
|
||||
PT_WAIT_UNTIL(pt, timer_expired(&input_timer));
|
||||
|
||||
press_key('2');
|
||||
|
||||
timer_set(&input_timer, 500);
|
||||
PT_WAIT_UNTIL(pt, timer_expired(&input_timer));
|
||||
|
||||
press_key('3');
|
||||
|
||||
timer_set(&input_timer, 2000);
|
||||
PT_WAIT_UNTIL(pt, timer_expired(&input_timer));
|
||||
|
||||
PT_END(pt);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/*
|
||||
* This is the main function. It initializes the two protothread
|
||||
* control structures and schedules the two protothreads. The main
|
||||
* function returns when the protothread the runs the code lock exits.
|
||||
*/
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
/*
|
||||
* Initialize the two protothread control structures.
|
||||
*/
|
||||
PT_INIT(&input_pt);
|
||||
PT_INIT(&codelock_pt);
|
||||
|
||||
/*
|
||||
* Schedule the two protothreads until the codelock_thread() exits.
|
||||
*/
|
||||
while(PT_SCHEDULE(codelock_thread(&codelock_pt))) {
|
||||
PT_SCHEDULE(input_thread(&input_pt));
|
||||
|
||||
/*
|
||||
* When running this example on a multitasking system, we must
|
||||
* give other processes a chance to run too and therefore we call
|
||||
* usleep() resp. Sleep() here. On a dedicated embedded system,
|
||||
* we usually do not need to do this.
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
Sleep(0);
|
||||
#else
|
||||
usleep(10);
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/*
|
||||
* Finally, the implementation of the simple timer library follows.
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
|
||||
static int clock_time(void)
|
||||
{ return (int)GetTickCount(); }
|
||||
|
||||
#else /* _WIN32 */
|
||||
|
||||
static int clock_time(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
struct timezone tz;
|
||||
gettimeofday(&tv, &tz);
|
||||
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
||||
}
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
static int timer_expired(struct timer *t)
|
||||
{ return (int)(clock_time() - t->start) >= (int)t->interval; }
|
||||
|
||||
static void timer_set(struct timer *t, int interval)
|
||||
{ t->interval = interval; t->start = clock_time(); }
|
||||
/*---------------------------------------------------------------------------*/
|
||||
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* This is a very small example that shows how to use
|
||||
* protothreads. The program consists of two protothreads that wait
|
||||
* for each other to toggle a variable.
|
||||
*/
|
||||
|
||||
/* We must always include pt.h in our protothreads code. */
|
||||
#include "pt.h"
|
||||
|
||||
#include <stdio.h> /* For printf(). */
|
||||
|
||||
/* Two flags that the two protothread functions use. */
|
||||
static int protothread1_flag, protothread2_flag;
|
||||
|
||||
/**
|
||||
* The first protothread function. A protothread function must always
|
||||
* return an integer, but must never explicitly return - returning is
|
||||
* performed inside the protothread statements.
|
||||
*
|
||||
* The protothread function is driven by the main loop further down in
|
||||
* the code.
|
||||
*/
|
||||
static int
|
||||
protothread1(struct pt *pt)
|
||||
{
|
||||
/* A protothread function must begin with PT_BEGIN() which takes a
|
||||
pointer to a struct pt. */
|
||||
PT_BEGIN(pt);
|
||||
|
||||
/* We loop forever here. */
|
||||
while(1) {
|
||||
/* Wait until the other protothread has set its flag. */
|
||||
PT_WAIT_UNTIL(pt, protothread2_flag != 0);
|
||||
printf("Protothread 1 running\n");
|
||||
|
||||
/* We then reset the other protothread's flag, and set our own
|
||||
flag so that the other protothread can run. */
|
||||
protothread2_flag = 0;
|
||||
protothread1_flag = 1;
|
||||
|
||||
/* And we loop. */
|
||||
}
|
||||
|
||||
/* All protothread functions must end with PT_END() which takes a
|
||||
pointer to a struct pt. */
|
||||
PT_END(pt);
|
||||
}
|
||||
|
||||
/**
|
||||
* The second protothread function. This is almost the same as the
|
||||
* first one.
|
||||
*/
|
||||
static int
|
||||
protothread2(struct pt *pt)
|
||||
{
|
||||
PT_BEGIN(pt);
|
||||
|
||||
while(1) {
|
||||
/* Let the other protothread run. */
|
||||
protothread2_flag = 1;
|
||||
|
||||
/* Wait until the other protothread has set its flag. */
|
||||
PT_WAIT_UNTIL(pt, protothread1_flag != 0);
|
||||
printf("Protothread 2 running\n");
|
||||
|
||||
/* We then reset the other protothread's flag. */
|
||||
protothread1_flag = 0;
|
||||
|
||||
/* And we loop. */
|
||||
}
|
||||
PT_END(pt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finally, we have the main loop. Here is where the protothreads are
|
||||
* initialized and scheduled. First, however, we define the
|
||||
* protothread state variables pt1 and pt2, which hold the state of
|
||||
* the two protothreads.
|
||||
*/
|
||||
static struct pt pt1, pt2;
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
/* Initialize the protothread state variables with PT_INIT(). */
|
||||
PT_INIT(&pt1);
|
||||
PT_INIT(&pt2);
|
||||
|
||||
/*
|
||||
* Then we schedule the two protothreads by repeatedly calling their
|
||||
* protothread functions and passing a pointer to the protothread
|
||||
* state variables as arguments.
|
||||
*/
|
||||
while(1) {
|
||||
protothread1(&pt1);
|
||||
protothread2(&pt2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2005, Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
* $Id: lc-addrlabels.h,v 1.4 2006/06/03 11:29:43 adam Exp $
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup lc
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Implementation of local continuations based on the "Labels as
|
||||
* values" feature of gcc
|
||||
* \author
|
||||
* Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
* This implementation of local continuations is based on a special
|
||||
* feature of the GCC C compiler called "labels as values". This
|
||||
* feature allows assigning pointers with the address of the code
|
||||
* corresponding to a particular C label.
|
||||
*
|
||||
* For more information, see the GCC documentation:
|
||||
* http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __LC_ADDRLABELS_H__
|
||||
#define __LC_ADDRLABELS_H__
|
||||
|
||||
/** \hideinitializer */
|
||||
typedef void * lc_t;
|
||||
|
||||
#define LC_INIT(s) s = NULL
|
||||
|
||||
#define LC_RESUME(s) \
|
||||
do { \
|
||||
if(s != NULL) { \
|
||||
goto *s; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define LC_CONCAT2(s1, s2) s1##s2
|
||||
#define LC_CONCAT(s1, s2) LC_CONCAT2(s1, s2)
|
||||
|
||||
#define LC_SET(s) \
|
||||
do { \
|
||||
LC_CONCAT(LC_LABEL, __LINE__): \
|
||||
(s) = &&LC_CONCAT(LC_LABEL, __LINE__); \
|
||||
} while(0)
|
||||
|
||||
#define LC_END(s)
|
||||
|
||||
#endif /* __LC_ADDRLABELS_H__ */
|
||||
/** @} */
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2005, Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
* $Id: lc-switch.h,v 1.4 2006/06/03 11:29:43 adam Exp $
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup lc
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Implementation of local continuations based on switch() statment
|
||||
* \author Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
* This implementation of local continuations uses the C switch()
|
||||
* statement to resume execution of a function somewhere inside the
|
||||
* function's body. The implementation is based on the fact that
|
||||
* switch() statements are able to jump directly into the bodies of
|
||||
* control structures such as if() or while() statmenets.
|
||||
*
|
||||
* This implementation borrows heavily from Simon Tatham's coroutines
|
||||
* implementation in C:
|
||||
* http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
|
||||
*/
|
||||
|
||||
#ifndef __LC_SWITCH_H__
|
||||
#define __LC_SWITCH_H__
|
||||
|
||||
/* WARNING! lc implementation using switch() does not work if an
|
||||
LC_SET() is done within another switch() statement! */
|
||||
|
||||
/** \hideinitializer */
|
||||
typedef unsigned short lc_t;
|
||||
|
||||
#define LC_INIT(s) s = 0;
|
||||
|
||||
#define LC_RESUME(s) switch(s) { case 0:
|
||||
|
||||
#define LC_SET(s) s = __LINE__; case __LINE__:
|
||||
|
||||
#define LC_END(s) }
|
||||
|
||||
#endif /* __LC_SWITCH_H__ */
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2005, Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the protothreads library.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
* $Id: lc.h,v 1.2 2005/02/24 10:36:59 adam Exp $
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup pt
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \defgroup lc Local continuations
|
||||
* @{
|
||||
*
|
||||
* Local continuations form the basis for implementing protothreads. A
|
||||
* local continuation can be <i>set</i> in a specific function to
|
||||
* capture the state of the function. After a local continuation has
|
||||
* been set can be <i>resumed</i> in order to restore the state of the
|
||||
* function at the point where the local continuation was set.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file lc.h
|
||||
* Local continuations
|
||||
* \author
|
||||
* Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef DOXYGEN
|
||||
/**
|
||||
* Initialize a local continuation.
|
||||
*
|
||||
* This operation initializes the local continuation, thereby
|
||||
* unsetting any previously set continuation state.
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define LC_INIT(lc)
|
||||
|
||||
/**
|
||||
* Set a local continuation.
|
||||
*
|
||||
* The set operation saves the state of the function at the point
|
||||
* where the operation is executed. As far as the set operation is
|
||||
* concerned, the state of the function does <b>not</b> include the
|
||||
* call-stack or local (automatic) variables, but only the program
|
||||
* counter and such CPU registers that needs to be saved.
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define LC_SET(lc)
|
||||
|
||||
/**
|
||||
* Resume a local continuation.
|
||||
*
|
||||
* The resume operation resumes a previously set local continuation, thus
|
||||
* restoring the state in which the function was when the local
|
||||
* continuation was set. If the local continuation has not been
|
||||
* previously set, the resume operation does nothing.
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define LC_RESUME(lc)
|
||||
|
||||
/**
|
||||
* Mark the end of local continuation usage.
|
||||
*
|
||||
* The end operation signifies that local continuations should not be
|
||||
* used any more in the function. This operation is not needed for
|
||||
* most implementations of local continuation, but is required by a
|
||||
* few implementations.
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define LC_END(lc)
|
||||
|
||||
/**
|
||||
* \var typedef lc_t;
|
||||
*
|
||||
* The local continuation type.
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#endif /* DOXYGEN */
|
||||
|
||||
#ifndef __LC_H__
|
||||
#define __LC_H__
|
||||
|
||||
|
||||
#ifdef LC_INCLUDE
|
||||
#include LC_INCLUDE
|
||||
#else
|
||||
#include "lc-switch.h"
|
||||
#endif /* LC_INCLUDE */
|
||||
|
||||
#endif /* __LC_H__ */
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
||||
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the protothreads library.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
* $Id: pt-sem.h,v 1.2 2005/02/24 10:36:59 adam Exp $
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup pt
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \defgroup ptsem Protothread semaphores
|
||||
* @{
|
||||
*
|
||||
* This module implements counting semaphores on top of
|
||||
* protothreads. Semaphores are a synchronization primitive that
|
||||
* provide two operations: "wait" and "signal". The "wait" operation
|
||||
* checks the semaphore counter and blocks the thread if the counter
|
||||
* is zero. The "signal" operation increases the semaphore counter but
|
||||
* does not block. If another thread has blocked waiting for the
|
||||
* semaphore that is signalled, the blocked thread will become
|
||||
* runnable again.
|
||||
*
|
||||
* Semaphores can be used to implement other, more structured,
|
||||
* synchronization primitives such as monitors and message
|
||||
* queues/bounded buffers (see below).
|
||||
*
|
||||
* The following example shows how the producer-consumer problem, also
|
||||
* known as the bounded buffer problem, can be solved using
|
||||
* protothreads and semaphores. Notes on the program follow after the
|
||||
* example.
|
||||
*
|
||||
\code
|
||||
#include "pt-sem.h"
|
||||
|
||||
#define NUM_ITEMS 32
|
||||
#define BUFSIZE 8
|
||||
|
||||
static struct pt_sem mutex, full, empty;
|
||||
|
||||
PT_THREAD(producer(struct pt *pt))
|
||||
{
|
||||
static int produced;
|
||||
|
||||
PT_BEGIN(pt);
|
||||
|
||||
for(produced = 0; produced < NUM_ITEMS; ++produced) {
|
||||
|
||||
PT_SEM_WAIT(pt, &full);
|
||||
|
||||
PT_SEM_WAIT(pt, &mutex);
|
||||
add_to_buffer(produce_item());
|
||||
PT_SEM_SIGNAL(pt, &mutex);
|
||||
|
||||
PT_SEM_SIGNAL(pt, &empty);
|
||||
}
|
||||
|
||||
PT_END(pt);
|
||||
}
|
||||
|
||||
PT_THREAD(consumer(struct pt *pt))
|
||||
{
|
||||
static int consumed;
|
||||
|
||||
PT_BEGIN(pt);
|
||||
|
||||
for(consumed = 0; consumed < NUM_ITEMS; ++consumed) {
|
||||
|
||||
PT_SEM_WAIT(pt, &empty);
|
||||
|
||||
PT_SEM_WAIT(pt, &mutex);
|
||||
consume_item(get_from_buffer());
|
||||
PT_SEM_SIGNAL(pt, &mutex);
|
||||
|
||||
PT_SEM_SIGNAL(pt, &full);
|
||||
}
|
||||
|
||||
PT_END(pt);
|
||||
}
|
||||
|
||||
PT_THREAD(driver_thread(struct pt *pt))
|
||||
{
|
||||
static struct pt pt_producer, pt_consumer;
|
||||
|
||||
PT_BEGIN(pt);
|
||||
|
||||
PT_SEM_INIT(&empty, 0);
|
||||
PT_SEM_INIT(&full, BUFSIZE);
|
||||
PT_SEM_INIT(&mutex, 1);
|
||||
|
||||
PT_INIT(&pt_producer);
|
||||
PT_INIT(&pt_consumer);
|
||||
|
||||
PT_WAIT_THREAD(pt, producer(&pt_producer) &
|
||||
consumer(&pt_consumer));
|
||||
|
||||
PT_END(pt);
|
||||
}
|
||||
\endcode
|
||||
*
|
||||
* The program uses three protothreads: one protothread that
|
||||
* implements the consumer, one thread that implements the producer,
|
||||
* and one protothread that drives the two other protothreads. The
|
||||
* program uses three semaphores: "full", "empty" and "mutex". The
|
||||
* "mutex" semaphore is used to provide mutual exclusion for the
|
||||
* buffer, the "empty" semaphore is used to block the consumer is the
|
||||
* buffer is empty, and the "full" semaphore is used to block the
|
||||
* producer is the buffer is full.
|
||||
*
|
||||
* The "driver_thread" holds two protothread state variables,
|
||||
* "pt_producer" and "pt_consumer". It is important to note that both
|
||||
* these variables are declared as <i>static</i>. If the static
|
||||
* keyword is not used, both variables are stored on the stack. Since
|
||||
* protothreads do not store the stack, these variables may be
|
||||
* overwritten during a protothread wait operation. Similarly, both
|
||||
* the "consumer" and "producer" protothreads declare their local
|
||||
* variables as static, to avoid them being stored on the stack.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Couting semaphores implemented on protothreads
|
||||
* \author
|
||||
* Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __PT_SEM_H__
|
||||
#define __PT_SEM_H__
|
||||
|
||||
#include "pt.h"
|
||||
|
||||
struct pt_sem {
|
||||
unsigned int count;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize a semaphore
|
||||
*
|
||||
* This macro initializes a semaphore with a value for the
|
||||
* counter. Internally, the semaphores use an "unsigned int" to
|
||||
* represent the counter, and therefore the "count" argument should be
|
||||
* within range of an unsigned int.
|
||||
*
|
||||
* \param s (struct pt_sem *) A pointer to the pt_sem struct
|
||||
* representing the semaphore
|
||||
*
|
||||
* \param c (unsigned int) The initial count of the semaphore.
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define PT_SEM_INIT(s, c) (s)->count = c
|
||||
|
||||
/**
|
||||
* Wait for a semaphore
|
||||
*
|
||||
* This macro carries out the "wait" operation on the semaphore. The
|
||||
* wait operation causes the protothread to block while the counter is
|
||||
* zero. When the counter reaches a value larger than zero, the
|
||||
* protothread will continue.
|
||||
*
|
||||
* \param pt (struct pt *) A pointer to the protothread (struct pt) in
|
||||
* which the operation is executed.
|
||||
*
|
||||
* \param s (struct pt_sem *) A pointer to the pt_sem struct
|
||||
* representing the semaphore
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define PT_SEM_WAIT(pt, s) \
|
||||
do { \
|
||||
PT_WAIT_UNTIL(pt, (s)->count > 0); \
|
||||
--(s)->count; \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
* Signal a semaphore
|
||||
*
|
||||
* This macro carries out the "signal" operation on the semaphore. The
|
||||
* signal operation increments the counter inside the semaphore, which
|
||||
* eventually will cause waiting protothreads to continue executing.
|
||||
*
|
||||
* \param pt (struct pt *) A pointer to the protothread (struct pt) in
|
||||
* which the operation is executed.
|
||||
*
|
||||
* \param s (struct pt_sem *) A pointer to the pt_sem struct
|
||||
* representing the semaphore
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define PT_SEM_SIGNAL(pt, s) ++(s)->count
|
||||
|
||||
#endif /* __PT_SEM_H__ */
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
||||
|
||||
@@ -0,0 +1,328 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2005, Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
* $Id: pt.h,v 1.7 2006/10/02 07:52:56 adam Exp $
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup pt
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Protothreads implementation.
|
||||
* \author
|
||||
* Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __PT_H__
|
||||
#define __PT_H__
|
||||
|
||||
#include "lc.h"
|
||||
#include "stdint.h"
|
||||
#include "stdbool.h"
|
||||
|
||||
struct pt {
|
||||
lc_t lc;
|
||||
uint8_t status;
|
||||
};
|
||||
|
||||
typedef struct pt pt_t;
|
||||
|
||||
#define PT_WAITING 0
|
||||
#define PT_YIELDED 1
|
||||
#define PT_EXITED 2
|
||||
#define PT_ENDED 3
|
||||
|
||||
/**
|
||||
* \name Initialization
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Initialize a protothread.
|
||||
*
|
||||
* Initializes a protothread. Initialization must be done prior to
|
||||
* starting to execute the protothread.
|
||||
*
|
||||
* \param pt A pointer to the protothread control structure.
|
||||
*
|
||||
* \sa PT_SPAWN()
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define PT_INIT(pt) LC_INIT((pt)->lc)
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* \name Declaration and definition
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Declaration of a protothread.
|
||||
*
|
||||
* This macro is used to declare a protothread. All protothreads must
|
||||
* be declared with this macro.
|
||||
*
|
||||
* \param name_args The name and arguments of the C function
|
||||
* implementing the protothread.
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define PT_THREAD(name_args) char name_args
|
||||
|
||||
/**
|
||||
* Declare the start of a protothread inside the C function
|
||||
* implementing the protothread.
|
||||
*
|
||||
* This macro is used to declare the starting point of a
|
||||
* protothread. It should be placed at the start of the function in
|
||||
* which the protothread runs. All C statements above the PT_BEGIN()
|
||||
* invokation will be executed each time the protothread is scheduled.
|
||||
*
|
||||
* \param pt A pointer to the protothread control structure.
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define PT_BEGIN(pt) { char PT_YIELD_FLAG = 1; (void)PT_YIELD_FLAG; LC_RESUME((pt)->lc)
|
||||
|
||||
/**
|
||||
* Declare the end of a protothread.
|
||||
*
|
||||
* This macro is used for declaring that a protothread ends. It must
|
||||
* always be used together with a matching PT_BEGIN() macro.
|
||||
*
|
||||
* \param pt A pointer to the protothread control structure.
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define PT_END(pt) LC_END((pt)->lc); PT_YIELD_FLAG = 0; \
|
||||
PT_INIT(pt); return PT_ENDED; }
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* \name Blocked wait
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Block and wait until condition is true.
|
||||
*
|
||||
* This macro blocks the protothread until the specified condition is
|
||||
* true.
|
||||
*
|
||||
* \param pt A pointer to the protothread control structure.
|
||||
* \param condition The condition.
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define PT_WAIT_UNTIL(pt, condition) \
|
||||
do { \
|
||||
LC_SET((pt)->lc); \
|
||||
if(!(condition)) { \
|
||||
return PT_WAITING; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
* Block and wait while condition is true.
|
||||
*
|
||||
* This function blocks and waits while condition is true. See
|
||||
* PT_WAIT_UNTIL().
|
||||
*
|
||||
* \param pt A pointer to the protothread control structure.
|
||||
* \param cond The condition.
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define PT_WAIT_WHILE(pt, cond) PT_WAIT_UNTIL((pt), !(cond))
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* \name Hierarchical protothreads
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Block and wait until a child protothread completes.
|
||||
*
|
||||
* This macro schedules a child protothread. The current protothread
|
||||
* will block until the child protothread completes.
|
||||
*
|
||||
* \note The child protothread must be manually initialized with the
|
||||
* PT_INIT() function before this function is used.
|
||||
*
|
||||
* \param pt A pointer to the protothread control structure.
|
||||
* \param thread The child protothread with arguments
|
||||
*
|
||||
* \sa PT_SPAWN()
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define PT_WAIT_THREAD(pt, thread) PT_WAIT_WHILE((pt), PT_SCHEDULE(thread))
|
||||
|
||||
/**
|
||||
* Spawn a child protothread and wait until it exits.
|
||||
*
|
||||
* This macro spawns a child protothread and waits until it exits. The
|
||||
* macro can only be used within a protothread.
|
||||
*
|
||||
* \param pt A pointer to the protothread control structure.
|
||||
* \param child A pointer to the child protothread's control structure.
|
||||
* \param thread The child protothread with arguments
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define PT_SPAWN(pt, child, thread) \
|
||||
do { \
|
||||
PT_INIT((child)); \
|
||||
PT_WAIT_THREAD((pt), (thread)); \
|
||||
} while(0)
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* \name Exiting and restarting
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Restart the protothread.
|
||||
*
|
||||
* This macro will block and cause the running protothread to restart
|
||||
* its execution at the place of the PT_BEGIN() call.
|
||||
*
|
||||
* \param pt A pointer to the protothread control structure.
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define PT_RESTART(pt) \
|
||||
do { \
|
||||
PT_INIT(pt); \
|
||||
return PT_WAITING; \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
* Exit the protothread.
|
||||
*
|
||||
* This macro causes the protothread to exit. If the protothread was
|
||||
* spawned by another protothread, the parent protothread will become
|
||||
* unblocked and can continue to run.
|
||||
*
|
||||
* \param pt A pointer to the protothread control structure.
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define PT_EXIT(pt) \
|
||||
do { \
|
||||
PT_INIT(pt); \
|
||||
return PT_EXITED; \
|
||||
} while(0)
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* \name Calling a protothread
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Schedule a protothread.
|
||||
*
|
||||
* This function shedules a protothread. The return value of the
|
||||
* function is non-zero if the protothread is running or zero if the
|
||||
* protothread has exited.
|
||||
*
|
||||
* \param f The call to the C function implementing the protothread to
|
||||
* be scheduled
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define PT_SCHEDULE(f) ((f) < PT_EXITED)
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* \name Yielding from a protothread
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Yield from the current protothread.
|
||||
*
|
||||
* This function will yield the protothread, thereby allowing other
|
||||
* processing to take place in the system.
|
||||
*
|
||||
* \param pt A pointer to the protothread control structure.
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define PT_YIELD(pt) \
|
||||
do { \
|
||||
PT_YIELD_FLAG = 0; \
|
||||
LC_SET((pt)->lc); \
|
||||
if(PT_YIELD_FLAG == 0) { \
|
||||
return PT_YIELDED; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
* \brief Yield from the protothread until a condition occurs.
|
||||
* \param pt A pointer to the protothread control structure.
|
||||
* \param cond The condition.
|
||||
*
|
||||
* This function will yield the protothread, until the
|
||||
* specified condition evaluates to true.
|
||||
*
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define PT_YIELD_UNTIL(pt, cond) \
|
||||
do { \
|
||||
PT_YIELD_FLAG = 0; \
|
||||
LC_SET((pt)->lc); \
|
||||
if((PT_YIELD_FLAG == 0) || !(cond)) { \
|
||||
return PT_YIELDED; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif /* __PT_H__ */
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Your Name.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* This file implements the extensions to the protothreads library.
|
||||
*
|
||||
* Author: Your Name <your.email@example.com>
|
||||
*/
|
||||
|
||||
#include "pt_ext.h"
|
||||
|
||||
/**
|
||||
* Global tick counter.
|
||||
*
|
||||
* This variable is used to track system ticks. It should be incremented
|
||||
* by the system tick interrupt or a similar mechanism.
|
||||
*/
|
||||
volatile unsigned int pt_ticks = 0;
|
||||
|
||||
/**
|
||||
* Increment the system tick counter.
|
||||
*/
|
||||
void
|
||||
pt_ticks_inc(void)
|
||||
{
|
||||
pt_ticks++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current system tick counter.
|
||||
*
|
||||
* \return The current tick count.
|
||||
*/
|
||||
unsigned int
|
||||
pt_ticks_get(void)
|
||||
{
|
||||
return pt_ticks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if timeout has occurred, handling tick counter overflow.
|
||||
*/
|
||||
int
|
||||
pt_is_timeout(unsigned int start, unsigned int end, unsigned int timeout)
|
||||
{
|
||||
return (end - start) >= timeout ||
|
||||
((end < start) && (UINT_MAX - start + end + 1) >= timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the protothreads extensions.
|
||||
*
|
||||
* This function resets the global tick counter to zero.
|
||||
*/
|
||||
void
|
||||
pt_ext_init(void)
|
||||
{
|
||||
pt_ticks = 0;
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Your Name.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* This file is an extension to the protothreads library.
|
||||
*
|
||||
* Author: Your Name <your.email@example.com>
|
||||
*/
|
||||
|
||||
#ifndef __PT_EXT_H__
|
||||
#define __PT_EXT_H__
|
||||
|
||||
#include "pt.h"
|
||||
#include "limits.h"
|
||||
|
||||
#define PT_WAIT_STAT_SUCC (0 )
|
||||
#define PT_WAIT_STAT_TIMEOUT (-2)
|
||||
|
||||
/**
|
||||
* \addtogroup pt
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Increment the system tick counter.
|
||||
*
|
||||
* This macro increments the global tick counter. It should be called
|
||||
* from a system tick interrupt or similar context.
|
||||
*/
|
||||
|
||||
void pt_ticks_inc(void);
|
||||
|
||||
/**
|
||||
* Get the current system tick counter.
|
||||
*
|
||||
* \return The current tick count.
|
||||
*/
|
||||
unsigned int pt_ticks_get(void);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Delay for a specified number of milliseconds.
|
||||
*
|
||||
* This macro blocks the protothread for the specified number of
|
||||
* milliseconds. The delay is implemented using the global tick counter.
|
||||
*
|
||||
* \param pt A pointer to the protothread control structure.
|
||||
* \param ms The number of milliseconds to delay.
|
||||
*/
|
||||
/**
|
||||
* Check if timeout has occurred, handling tick counter overflow.
|
||||
*
|
||||
* \param start The start tick count
|
||||
* \param end The end tick count
|
||||
* \param timeout The timeout value in ticks
|
||||
* \return 1 if timeout occurred, 0 otherwise
|
||||
*/
|
||||
int pt_is_timeout(unsigned int start, unsigned int end, unsigned int timeout);
|
||||
|
||||
#define PT_DELAY_MS(pt, ms) \
|
||||
do { \
|
||||
static unsigned int _pt_delay_start=0; \
|
||||
_pt_delay_start = pt_ticks_get(); \
|
||||
PT_WAIT_UNTIL((pt), pt_is_timeout(_pt_delay_start, pt_ticks_get(), ms)); \
|
||||
} while (0)
|
||||
|
||||
#define PT_WAIT(pt, c, timeout, result) \
|
||||
do { \
|
||||
static unsigned int _pt_wait_start = 0;\
|
||||
_pt_wait_start = pt_ticks_get(); \
|
||||
*result = -1; \
|
||||
PT_WAIT_UNTIL((pt), (c) || pt_is_timeout(_pt_wait_start, pt_ticks_get(), timeout)); \
|
||||
if (c) { *result = 0; };\
|
||||
if (pt_is_timeout(_pt_wait_start, pt_ticks_get(), timeout)) { *result = -2;};\
|
||||
}while (0)
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
||||
|
||||
#endif /* __PT_EXT_H__ */
|
||||
@@ -0,0 +1,105 @@
|
||||
|
||||
#include "pt_task.h"
|
||||
#include "pt_pm.h"
|
||||
#include "pt_ext.h"
|
||||
|
||||
#include "stdio.h"
|
||||
|
||||
// 系统空闲条件
|
||||
#define SYSTEM_IS_IDLE() (ALL_TASKS_IDLE())
|
||||
#define DEEP_SLEEP_THRESHOLD 5 // 进入深度休眠的空闲计数阈值
|
||||
|
||||
static struct {
|
||||
pm_adapter_t default_adapter;
|
||||
pt_t pt;
|
||||
pm_mode_t current_mode; // 当前功耗模式
|
||||
uint32_t ref_count[PM_SLEEP_MODE_MAX]; // 引用计数数组
|
||||
} pm;
|
||||
|
||||
static bool system_is_idle(void)
|
||||
{
|
||||
return pt_task_all_idle();
|
||||
}
|
||||
|
||||
/*
|
||||
功耗管理:遍历所有任务状态,然后根据用于请求的功耗模式,调用适配器接口,调整MCU的运行模式
|
||||
*/
|
||||
static void pt_pm_handler(void) {
|
||||
|
||||
if (system_is_idle()) {
|
||||
|
||||
// 切换到下一个可用的功耗模式
|
||||
pm_mode_t next_mode = PM_SLEEP_MODE_NONE;
|
||||
for (pm_mode_t m = PM_SLEEP_MODE_NONE; m < PM_SLEEP_MODE_MAX; m++) {
|
||||
if (pm.ref_count[m] > 0 ) {
|
||||
next_mode = m;
|
||||
}
|
||||
}
|
||||
|
||||
if (next_mode != pm.current_mode && pm.default_adapter.sleep) {
|
||||
pm.default_adapter.sleep(next_mode);
|
||||
pm.current_mode = next_mode;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
pt_pm_release(PM_SLEEP_MODE_NONE); // 唤醒系统
|
||||
|
||||
if (pm.default_adapter.wakeup) {
|
||||
pm.default_adapter.wakeup();
|
||||
}
|
||||
pm.current_mode = PM_SLEEP_MODE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void pt_pm_adapter_init(pm_adapter_t *adapter) {
|
||||
if (adapter) {
|
||||
pm.default_adapter = *adapter; // 复制整个结构体
|
||||
} else {
|
||||
pm.default_adapter.sleep = 0;
|
||||
pm.default_adapter.wakeup = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void pt_pm_init(void) {
|
||||
|
||||
PT_INIT(&pm.pt);
|
||||
}
|
||||
|
||||
|
||||
int pt_task_pm(void) {
|
||||
|
||||
PT_BEGIN(&pm.pt);
|
||||
|
||||
while (1) {
|
||||
|
||||
pt_pm_handler(); // 处理功耗状态
|
||||
|
||||
PT_DELAY_MS(&pm.pt, system_is_idle() ? 1000 : 100);
|
||||
}
|
||||
|
||||
PT_END(&pm.pt);
|
||||
}
|
||||
|
||||
/*
|
||||
请求功耗模式:引用计数自增,如果为1,则调用适配器接口,调整MCU的运行模式
|
||||
*/
|
||||
void pt_pm_request(pm_mode_t mode) {
|
||||
if (mode >= PM_SLEEP_MODE_MAX) {
|
||||
return; // 无效模式
|
||||
}
|
||||
pm.ref_count[mode]++; // 仅操作引用计数
|
||||
}
|
||||
|
||||
/*
|
||||
释放功耗模式:引用计数自减,如果为0,则调用适配器接口,调整MCU的运行模式
|
||||
*/
|
||||
void pt_pm_release(pm_mode_t mode) {
|
||||
if (mode >= PM_SLEEP_MODE_MAX) {
|
||||
return; // 无效模式
|
||||
}
|
||||
if (pm.ref_count[mode] > 0) {
|
||||
pm.ref_count[mode]--; // 仅操作引用计数
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#ifndef PT_PM_H
|
||||
#define PT_PM_H
|
||||
|
||||
#include "pt_task.h"
|
||||
|
||||
typedef enum {
|
||||
PM_SLEEP_MODE_NONE,
|
||||
PM_SLEEP_MODE_IDLE,
|
||||
PM_SLEEP_MODE_LIGHT,
|
||||
PM_SLEEP_MODE_DEEP,
|
||||
PM_SLEEP_MODE_STANDBY,
|
||||
PM_SLEEP_MODE_POWER_DOWN,
|
||||
PM_SLEEP_MODE_MAX
|
||||
} pm_mode_t;
|
||||
|
||||
typedef struct {
|
||||
void (*sleep)(pm_mode_t mode);
|
||||
void (*wakeup)(void);
|
||||
} pm_adapter_t;
|
||||
|
||||
extern void pt_pm_adapter_init(pm_adapter_t *adapter);
|
||||
|
||||
extern void pt_pm_init(void);
|
||||
|
||||
extern void pt_pm_request(pm_mode_t mode);
|
||||
|
||||
extern void pt_pm_release(pm_mode_t mode);
|
||||
|
||||
extern int pt_task_pm(void);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the protothreads library.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
* $Id: pt-sem.h,v 1.2 2005/02/24 10:36:59 adam Exp $
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup pt
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \defgroup ptsem Protothread semaphores
|
||||
* @{
|
||||
*
|
||||
* This module implements counting semaphores on top of
|
||||
* protothreads. Semaphores are a synchronization primitive that
|
||||
* provide two operations: "wait" and "signal". The "wait" operation
|
||||
* checks the semaphore counter and blocks the thread if the counter
|
||||
* is zero. The "signal" operation increases the semaphore counter but
|
||||
* does not block. If another thread has blocked waiting for the
|
||||
* semaphore that is signalled, the blocked thread will become
|
||||
* runnable again.
|
||||
*
|
||||
* Semaphores can be used to implement other, more structured,
|
||||
* synchronization primitives such as monitors and message
|
||||
* queues/bounded buffers (see below).
|
||||
*
|
||||
* The following example shows how the producer-consumer problem, also
|
||||
* known as the bounded buffer problem, can be solved using
|
||||
* protothreads and semaphores. Notes on the program follow after the
|
||||
* example.
|
||||
*
|
||||
\code
|
||||
#include "pt-sem.h"
|
||||
|
||||
#define NUM_ITEMS 32
|
||||
#define BUFSIZE 8
|
||||
|
||||
static struct pt_sem mutex, full, empty;
|
||||
|
||||
PT_THREAD(producer(struct pt *pt))
|
||||
{
|
||||
static int produced;
|
||||
|
||||
PT_BEGIN(pt);
|
||||
|
||||
for(produced = 0; produced < NUM_ITEMS; ++produced) {
|
||||
|
||||
PT_SEM_WAIT(pt, &full);
|
||||
|
||||
PT_SEM_WAIT(pt, &mutex);
|
||||
add_to_buffer(produce_item());
|
||||
PT_SEM_SIGNAL(pt, &mutex);
|
||||
|
||||
PT_SEM_SIGNAL(pt, &empty);
|
||||
}
|
||||
|
||||
PT_END(pt);
|
||||
}
|
||||
|
||||
PT_THREAD(consumer(struct pt *pt))
|
||||
{
|
||||
static int consumed;
|
||||
|
||||
PT_BEGIN(pt);
|
||||
|
||||
for(consumed = 0; consumed < NUM_ITEMS; ++consumed) {
|
||||
|
||||
PT_SEM_WAIT(pt, &empty);
|
||||
|
||||
PT_SEM_WAIT(pt, &mutex);
|
||||
consume_item(get_from_buffer());
|
||||
PT_SEM_SIGNAL(pt, &mutex);
|
||||
|
||||
PT_SEM_SIGNAL(pt, &full);
|
||||
}
|
||||
|
||||
PT_END(pt);
|
||||
}
|
||||
|
||||
PT_THREAD(driver_thread(struct pt *pt))
|
||||
{
|
||||
static struct pt pt_producer, pt_consumer;
|
||||
|
||||
PT_BEGIN(pt);
|
||||
|
||||
PT_SEM_INIT(&empty, 0);
|
||||
PT_SEM_INIT(&full, BUFSIZE);
|
||||
PT_SEM_INIT(&mutex, 1);
|
||||
|
||||
PT_INIT(&pt_producer);
|
||||
PT_INIT(&pt_consumer);
|
||||
|
||||
PT_WAIT_THREAD(pt, producer(&pt_producer) &
|
||||
consumer(&pt_consumer));
|
||||
|
||||
PT_END(pt);
|
||||
}
|
||||
\endcode
|
||||
*
|
||||
* The program uses three protothreads: one protothread that
|
||||
* implements the consumer, one thread that implements the producer,
|
||||
* and one protothread that drives the two other protothreads. The
|
||||
* program uses three semaphores: "full", "empty" and "mutex". The
|
||||
* "mutex" semaphore is used to provide mutual exclusion for the
|
||||
* buffer, the "empty" semaphore is used to block the consumer is the
|
||||
* buffer is empty, and the "full" semaphore is used to block the
|
||||
* producer is the buffer is full.
|
||||
*
|
||||
* The "driver_thread" holds two protothread state variables,
|
||||
* "pt_producer" and "pt_consumer". It is important to note that both
|
||||
* these variables are declared as <i>static</i>. If the static
|
||||
* keyword is not used, both variables are stored on the stack. Since
|
||||
* protothreads do not store the stack, these variables may be
|
||||
* overwritten during a protothread wait operation. Similarly, both
|
||||
* the "consumer" and "producer" protothreads declare their local
|
||||
* variables as static, to avoid them being stored on the stack.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Couting semaphores implemented on protothreads
|
||||
* \author
|
||||
* Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __PT_SEM_H__
|
||||
#define __PT_SEM_H__
|
||||
|
||||
#include "pt.h"
|
||||
|
||||
struct pt_sem {
|
||||
unsigned int count;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize a semaphore
|
||||
*
|
||||
* This macro initializes a semaphore with a value for the
|
||||
* counter. Internally, the semaphores use an "unsigned int" to
|
||||
* represent the counter, and therefore the "count" argument should be
|
||||
* within range of an unsigned int.
|
||||
*
|
||||
* \param s (struct pt_sem *) A pointer to the pt_sem struct
|
||||
* representing the semaphore
|
||||
*
|
||||
* \param c (unsigned int) The initial count of the semaphore.
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define PT_SEM_INIT(s, c) (s)->count = c
|
||||
|
||||
/**
|
||||
* Wait for a semaphore
|
||||
*
|
||||
* This macro carries out the "wait" operation on the semaphore. The
|
||||
* wait operation causes the protothread to block while the counter is
|
||||
* zero. When the counter reaches a value larger than zero, the
|
||||
* protothread will continue.
|
||||
*
|
||||
* \param pt (struct pt *) A pointer to the protothread (struct pt) in
|
||||
* which the operation is executed.
|
||||
*
|
||||
* \param s (struct pt_sem *) A pointer to the pt_sem struct
|
||||
* representing the semaphore
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define PT_SEM_WAIT(pt, s) \
|
||||
do { \
|
||||
PT_WAIT_UNTIL(pt, (s)->count > 0); \
|
||||
--(s)->count; \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
* Signal a semaphore
|
||||
*
|
||||
* This macro carries out the "signal" operation on the semaphore. The
|
||||
* signal operation increments the counter inside the semaphore, which
|
||||
* eventually will cause waiting protothreads to continue executing.
|
||||
*
|
||||
* \param pt (struct pt *) A pointer to the protothread (struct pt) in
|
||||
* which the operation is executed.
|
||||
*
|
||||
* \param s (struct pt_sem *) A pointer to the pt_sem struct
|
||||
* representing the semaphore
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define PT_SEM_SIGNAL(pt, s) ++(s)->count
|
||||
|
||||
#endif /* __PT_SEM_H__ */
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Implementation of automatic protothreads initialization and scheduling
|
||||
*/
|
||||
|
||||
#include "pt_task.h"
|
||||
#include "stdio.h"
|
||||
|
||||
static int task_start_sch_entry(pt_t *p)
|
||||
{
|
||||
PT_BEGIN(p);
|
||||
|
||||
PT_END(p);
|
||||
}
|
||||
PT_TASK_START(task_start_sch_entry);
|
||||
|
||||
|
||||
static int task_end_sch_entry(pt_t *p)
|
||||
{
|
||||
PT_BEGIN(p);
|
||||
|
||||
|
||||
|
||||
PT_END(p);
|
||||
}
|
||||
PT_TASK_END(task_end_sch_entry);
|
||||
|
||||
bool pt_task_is_active(pt_task_t *task)
|
||||
{
|
||||
if( ( task->status < PT_WAITING ) &&
|
||||
(task->status< PT_EXITED) ){
|
||||
|
||||
return 1;
|
||||
|
||||
}else{
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Schedule all registered task functions
|
||||
*/
|
||||
void pt_task_schedule(void)
|
||||
{
|
||||
pt_task_t* start = (pt_task_t*) PT_TASK_OBJ_START;
|
||||
pt_task_t* end = (pt_task_t*) PT_TASK_OBJ_END;
|
||||
|
||||
for (pt_task_t* task = start; task < end; task++)
|
||||
{
|
||||
if (task->fn_entry && task->pt && task->status < PT_ENDED)
|
||||
{
|
||||
task->status = task->fn_entry(task->pt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool pt_task_all_idle(void)
|
||||
{
|
||||
bool is_idle = true;
|
||||
pt_task_t* start = (pt_task_t*)PT_TASK_OBJ_START;
|
||||
pt_task_t* end = (pt_task_t*)PT_TASK_OBJ_END;
|
||||
for (pt_task_t* task = start; task < end; task++) {
|
||||
if (task->pt && pt_task_is_active(task)) {
|
||||
is_idle = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return is_idle;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
#ifndef PT_TASK_H
|
||||
#define PT_TASK_H
|
||||
|
||||
#include "pt.h"
|
||||
|
||||
#include "pt_sem.h"
|
||||
|
||||
#include "pt_ext.h"
|
||||
|
||||
#include "pt_pm.h"
|
||||
|
||||
/*
|
||||
* Structure for registered entries
|
||||
* Contains the name, protothread control structure, and function pointers
|
||||
* for initialization and entry functions.
|
||||
*/
|
||||
typedef struct pt pt_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char name[24]; /* Entry name */
|
||||
pt_t* pt; /* Protothread control structure */
|
||||
int status;
|
||||
int (*fn_entry)(pt_t *pt); /* Function pointer */
|
||||
} pt_task_t;
|
||||
|
||||
|
||||
/*
|
||||
* Register a scheduling entry function
|
||||
* \param obj_name Unique identifier for the entry (max 7 chars)
|
||||
* \param pt_ptr Protothread control structure pointer
|
||||
* \param entry_func Entry point function (int (*)(pt_t *))
|
||||
*/
|
||||
/*
|
||||
* Register a scheduling entry function
|
||||
* @param obj_name Unique identifier for the entry (max 7 chars)
|
||||
* @param pt_ptr Protothread control structure pointer
|
||||
* @param init_func Initialization function (int (*)(pt_t *))
|
||||
* @param entry_func Entry point function (int (*)(pt_t *))
|
||||
*/
|
||||
#define PT_TASK_OBJ(obj_name) _pt_task_object_##obj_name
|
||||
|
||||
//#define PT_TASK_OBJ_DECL(obj_name) pt_task_t PT_TASK_OBJ(obj_name)
|
||||
|
||||
|
||||
/*
|
||||
* Specific section boundary accessors for PT_SCHEDULE_SECTION
|
||||
*/
|
||||
#ifdef __CC_ARM
|
||||
/* MDK ARM Compiler specific macros for PT_SCHEDULE_SECTION */
|
||||
#define PT_TASK_OBJ_START ((uint32_t)&PT_TASK_OBJ(start))
|
||||
#define PT_TASK_OBJ_END ((uint32_t)&PT_TASK_OBJ(end))
|
||||
#elif defined(__GNUC__)
|
||||
extern char __start_PT_SCHEDULE[];
|
||||
extern char __stop_PT_SCHEDULE[];
|
||||
#define PT_SCHEDULE_START (uint32_t)__start_PT_SCHEDULE
|
||||
#define PT_SCHEDULE_END (uint32_t)__stop_PT_SCHEDULE
|
||||
#endif
|
||||
|
||||
|
||||
#define PT_TASK_DECL(obj_name,level,entry_func) \
|
||||
static pt_t _pt_object_##obj_name; \
|
||||
static pt_task_t _pt_task_object_##obj_name\
|
||||
__attribute__((section("task._pt_obj_"#level), used)) = { \
|
||||
.name = #obj_name, \
|
||||
.pt = &(_pt_object_##obj_name), \
|
||||
.fn_entry =(entry_func) \
|
||||
}
|
||||
|
||||
|
||||
#define PT_TASK_START(entry_func) PT_TASK_DECL(start,"00",entry_func)
|
||||
|
||||
#define PT_TASK_BOARD_REG(entry_func) PT_TASK_DECL(entry_func,"01",entry_func)
|
||||
|
||||
#define PT_TASK_DRIVER_REG(entry_func) PT_TASK_DECL(entry_func,"02",entry_func)
|
||||
|
||||
#define PT_TASK_DEVICE_REG(entry_func) PT_TASK_DECL(entry_func,"03",entry_func)
|
||||
|
||||
#define PT_TASK_COMPONENT_REG(entry_func) PT_TASK_DECL(entry_func,"04",entry_func)
|
||||
|
||||
#define PT_TASK_THID_REG(entry_func) PT_TASK_DECL(entry_func,"05",entry_func)
|
||||
|
||||
#define PT_TASK_APP_REG(entry_func) PT_TASK_DECL(entry_func,"06",entry_func)
|
||||
|
||||
#define PT_TASK_END(entry_func) PT_TASK_DECL(end,"99",entry_func)
|
||||
|
||||
/*
|
||||
* Prototypes for auto management functions
|
||||
*/
|
||||
void pt_task_init(void);
|
||||
|
||||
void pt_task_schedule(void);
|
||||
|
||||
bool pt_task_is_active(pt_task_t *task);
|
||||
|
||||
bool pt_task_all_idle(void);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||