Compare commits

..

20 Commits

Author SHA1 Message Date
patacongo
13f01b4cf3 update
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@182 42af7a65-404d-4744-a932-0658087f49c3
2007-03-30 13:21:20 +00:00
patacongo
d2410c93c6 Fix another potential pthread_join race condition
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@181 42af7a65-404d-4744-a932-0658087f49c3
2007-03-30 13:11:19 +00:00
patacongo
f29250c671 Correct a race condition in the pthread join logic. Sometimes the join structure was being deallocated while it was still needed.
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@180 42af7a65-404d-4744-a932-0658087f49c3
2007-03-30 00:49:11 +00:00
patacongo
2a929796b9 Add timed mqueue test.
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@179 42af7a65-404d-4744-a932-0658087f49c3
2007-03-29 23:44:55 +00:00
patacongo
b1127822ed Fix bugs detected by timed mqueue test.
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@178 42af7a65-404d-4744-a932-0658087f49c3
2007-03-29 23:43:54 +00:00
patacongo
448c7f4618 Container being deallocated before buffers in container. Caused memory leak.
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@177 42af7a65-404d-4744-a932-0658087f49c3
2007-03-29 16:53:03 +00:00
patacongo
ed4fe71b96 Updated test results
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@176 42af7a65-404d-4744-a932-0658087f49c3
2007-03-29 14:27:23 +00:00
patacongo
63f134f988 Wrong task state
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@175 42af7a65-404d-4744-a932-0658087f49c3
2007-03-29 14:22:29 +00:00
patacongo
8b9fcf354e Moved exclusion logic to a higher level so that printf output is more readable when the same stdout FILE* is shared
by many pthreads (tasks did not have this probablem because they have separate stdout streams).


git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@174 42af7a65-404d-4744-a932-0658087f49c3
2007-03-29 14:21:31 +00:00
patacongo
b1d5b6899a Signal mask is now inherited by both child tasks and threads; this has the side-effect of changing the initia
l state of all signals from blocked to unblocked.


git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@173 42af7a65-404d-4744-a932-0658087f49c3
2007-03-29 13:34:37 +00:00
patacongo
2aab4d3c3a Unmatched sched_lock()/sched_unlock()
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@172 42af7a65-404d-4744-a932-0658087f49c3
2007-03-29 13:32:13 +00:00
patacongo
b765d17818 Don't allow signals to wake up blocked task if the signal is blocked.
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@171 42af7a65-404d-4744-a932-0658087f49c3
2007-03-29 13:31:08 +00:00
patacongo
54339607da Block signals while pthread exits.
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@170 42af7a65-404d-4744-a932-0658087f49c3
2007-03-29 13:29:29 +00:00
patacongo
0c2ff4a47c typo
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@169 42af7a65-404d-4744-a932-0658087f49c3
2007-03-29 13:28:27 +00:00
patacongo
23dffb8f23 Eliminate warnings
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@168 42af7a65-404d-4744-a932-0658087f49c3
2007-03-29 13:27:43 +00:00
patacongo
0db3f5c256 task_delete() calls sched_unlock(); _exit must keep pre-emption disabled until pending queue emptied.
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@167 42af7a65-404d-4744-a932-0658087f49c3
2007-03-29 13:26:24 +00:00
patacongo
56f7399200 Added mq_timedsend() and mq_timedreceive()
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@166 42af7a65-404d-4744-a932-0658087f49c3
2007-03-29 13:25:18 +00:00
patacongo
5f5d5496d9 Update mq_send() and mq_receive() description
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@165 42af7a65-404d-4744-a932-0658087f49c3
2007-03-28 16:00:57 +00:00
patacongo
3e352ca10b mq_receive/send: Return appropriate errnos and stop waiting if signal received.
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@164 42af7a65-404d-4744-a932-0658087f49c3
2007-03-28 14:48:42 +00:00
patacongo
c5971231da updates
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@163 42af7a65-404d-4744-a932-0658087f49c3
2007-03-27 21:27:41 +00:00
42 changed files with 5660 additions and 3250 deletions

View File

@@ -89,8 +89,28 @@
* Added directories to hold board-specific header files
* Added directories to hold board-specific drivers
0.2.3 2007-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr>
0.2.3 2007-03-29 Gregory Nutt <spudmonkey@racsa.co.cr>
* mq_receive and mq_send now return errno's appropriately
* mq_receive and mq_send are now correctly awakened by signals.
* Fixed an unmatched sched_lock/unlock pair in task_delete().
* sched_lock must be called in _exit() because operation of
task_delete() can cause pending tasks to be merged and a
context switch to occur.
* Added mq_timedreceive() and mq_timedsend()
* signal mask is now inherited by both child tasks and threads.
* Improved sharebility of stdout among pthreads (only). Nothing
was broken, but by moving the mutual exclusion logic to a
higher level, the printf output is more readable.
* Fixed a bug in file system cleanup: A list was being deleted
before the buffers contained in the list.
* Fixed a bug in the wait-for-message-queue-not-empty logic.
* Added a test of timed mqueue operations; detected and corrected
some mqueue errors.
* Identified and corrected a race condition associated with
pthread_join. In the failure condition, memory was being
deallocated while still in use.
0.2.4 2007-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr>
* Started m68322

View File

@@ -8,7 +8,7 @@
<tr align="center" bgcolor="#e4e4e4">
<td>
<h1><big><font color="#3c34ec"><i>NuttX RTOS</i></font></big></h1>
<p>Last Updated: March 21, 2007</p>
<p>Last Updated: March 28, 2007</p>
</td>
</tr>
</table>
@@ -180,7 +180,7 @@
</table>
<p>
The fifth release of NuttX (nuttx-0.2.2) is avalable for download
The sixth release of NuttX (nuttx-0.2.3) is available for download
from the <a href="http://sourceforge.net/project/showfiles.php?group_id=189573">SourceForge</a>
website.
</p>
@@ -450,7 +450,29 @@ Other memory:
* Added directories to hold board-specific header files
* Added directories to hold board-specific drivers
0.2.3 2007-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr>
0.2.3 2007-03-29 Gregory Nutt <spudmonkey@racsa.co.cr>
* mq_receive and mq_send now return errno's appropriately
* mq_receive and mq_send are now correctly awakened by signals.
* Fixed an unmatched sched_lock/unlock pair in task_delete().
* sched_lock must be called in _exit() because operation of
task_delete() can cause pending tasks to be merged and a
context switch to occur.
* Added mq_timedreceive() and mq_timedsend()
* signal mask is now inherited by both child tasks and threads.
* Improved sharebility of stdout among pthreads (only). Nothing
was broken, but by moving the mutual exclusion logic to a
higher level, the printf output is more readable.
* Fixed a bug in file system cleanup: A list was being deleted
before the buffers contained in the list.
* Fixed a bug in the wait-for-message-queue-not-empty logic.
* Added a test of timed mqueue operations; detected and corrected
some mqueue errors.
* Identified and corrected a race condition associated with
pthread_join. In the failure condition, memory was being
deallocated while still in use.
0.2.4 2007-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr>
* Started m68322
</pre></ul>

View File

@@ -16,7 +16,7 @@
</b></big>
<p><small>by</small></p>
<p>Gregory Nutt</p>
<p><small>Last Update: March 22, 2007</small></p>
<p><small>Last Update: March 26, 2007</small></p>
</center>
<center><h1>Table of Contents</h1></center>
@@ -34,8 +34,11 @@
<ul>
<li><a href="#configsdirectorystructure">2.3.1 Subdirectory Structure</a></li>
<li><a href="#summaryofconfigfiles">2.3.2 Summary of Files</a></li>
<ul>
<li><a href="#boardlogic">2.3.2.1 Board Specific Logic</a></li>
<li><a href="#boardconfigfiles">2.3.2.2 Board Specific Configuration Files</a></li>
</ul>
<li><a href="#supportedboards">2.3.3 Supported Boards</a></li>
<li><a href="#configuringnuttx">2.3.4 Configuring NuttX</a></li>
</ul>
<li>2.4 <a href="#DirStructDrivers">drivers</a></li>
<li>2.5 <a href="#DirStructExamples">examples</a></li>
@@ -45,8 +48,13 @@
<li>2.9 <a href="#DirStructMm">mm</a></li>
<li>2.10 <a href="#DirStructSched">sched</a></li>
<li>2.11 <a href="#DirStructTools">tools</a></li>
<li>2.12 <a href="#topmakefile">Makefile</a></li>
</ul>
<li>3.0 <a href="#configandbuild">Configuring and Building</a></li>
<ul>
<li><a href="#configuringnuttx">3.1 Configuring NuttX</a></li>
<li><a href="#buildingnuttx">3.2 Building NuttX</a></li>
</ul>
<li>3.0 <a href="#DirectoryConfiAndBuild">Configuring and Building</a></li>
<li>4.0 <a href="#ArchAPIs">Architecture APIs</a></li>
<ul>
<li><a href="#imports">4.1 APIs Exported by Architecture-Specific Logic to NuttX</a></li>
@@ -88,7 +96,7 @@
into the build.
</p>
<p>
See also arch/README.txt.
See also <code>arch/README.txt</code> and <code>configs/README.txt</code>.
</p>
<p><b>General Philosophy</b>.
@@ -96,53 +104,66 @@
<hr>
<h1>2.0 <a name="DirectoryStructure">Directory Structure</a></h1>
<p>The general directly layout for NuttX is very similar to the directory structure
of the Linux kernel -- at least at the most superficial layers.
At the top level is the main makefile and a series of sub-directories identified
below and discussed in the following paragraphs:</p>
<p>
<b>Directory Structure</b>.
The general directly layout for NuttX is very similar to the directory structure
of the Linux kernel -- at least at the most superficial layers.
At the top level is the main makefile and a series of sub-directories identified
below and discussed in the following paragraphs:
</p>
<ul><pre>
.
|-- Makefile
|-- <a href="#topmakefile">Makefile</a>
|-- <a href="#DirStructDocumentation">Documentation</a>
| `-- <i>(documentation files)</i>
|-- <a href="#DirStructArch">arch</a>
| |-- <i>&lt;arch-name&gt;</i>
| | |-- include
| | `-- src
| `-- <i>&lt:;other-architectures&gt;</i>
|-- <a href="#DirStructConfigs">configs</a>
| |-- <i>&lt;board-name&gt;</i>
| | |-- Make.defs
| | |-- defconfig
| | `-- setenv.sh
| `-- <i>&lt:;other-architectures&gt;</i>
| `-- <i>(documentation files)</i>/
|-- <a href="#DirStructArch">arch</a>/
| |-- <i>&lt;arch-name&gt;</i>/
| | |-- include/
| | | |--<i>&lt;chip-name&gt;</i>/
| | | | `-- <i>(chip-specific header files)</i>
| | | |--<i>&lt;other-chips&gt;</i>/
| | | `-- <i>(architecture-specific header files)</i>
| | `-- src/
| | |--<i>&lt;chip-name&gt;</i>/
| | | `-- <i>(chip-specific source files)</i>
| | |--<i>&lt;other-chips&gt;</i>/
| | `-- <i>(architecture-specific source files)</i>
| `-- <i>&lt;other-architectures&gt;</i>/
|-- <a href="#DirStructConfigs">configs</a>/
| |-- <i>&lt;board-name&gt;</i>/
| | |-- include/
| | | `-- <i>(board-specific header files)</i>
| | |-- src/
| | | |-- Makefile
| | | `-- <i>(board-specific source files)</i>
| | `-- <i>(board-specific configuration files)</i>
| `-- <i>&lt;other-boards&gt;</i>/
|-- <a href="#DirStructDrivers">drivers</a>
| |-- Makefile
| `-- <i>(driver source files)</i>
|-- <a href="#DirStructExamples">examples</a>
| `-- <i>(example)</i>
| |-- Makefile/
| `-- <i>(common driver source files)</i>
|-- <a href="#DirStructExamples">examples</a>/
| `-- <i>(example)</i>/
| |-- Makefile
| `-- <i>(example source files)</i>
|-- <a href="#DirStructFs">fs</a>
|-- <a href="#DirStructFs">fs</a>/
| |-- Makefile
| `-- <i>(fs source files)</i>
|-- <a href="#DirStructInclude">include</a>
|-- <a href="#DirStructInclude">include</a>/
| |-- <i>(standard header files)</i>
| |-- nuttx
| |-- nuttx/
| | `-- <i>(nuttx specific header files)</i>
| `- sys
| `- sys/
| | `-- <i>(more standard header files)</i>
|-- <a href="#DirStructLib">lib</a>
|-- <a href="#DirStructLib">lib</a>/
| |-- Makefile
| `-- <i>(lib source files)</i>
|-- <a href="#DirStructMm">mm</a>
|-- <a href="#DirStructMm">mm</a>/
| |-- Makefile
| `-- <i>(mm source files)</i>
|-- <a href="#DirStructSched">sched</a>
|-- <a href="#DirStructSched">sched</a>/
| |-- Makefile
| `-- <i>(sched source files)</i>
`-- <a href="#DirStructDrivers">tools</a>
`-- <a href="#DirStructDrivers">tools</a>/
|-- Makefile.mkconfig
|-- configure.sh
|-- mkconfig.c
@@ -150,6 +171,40 @@ below and discussed in the following paragraphs:</p>
`-- zipme
</pre></ul>
<p>
<b>Configuration Files</b>.
The NuttX configuration consists of:
</p>
<ul>
<li>
<i>Processor architecture specific files</i>.
These are the files contained in the <code>arch/</code><i>&lt;arch-name&gt;</i><code>/</code> directory
and are discussed in a paragraph <a href="#archdirectorystructure">below</a>.
</li>
<li>
<i>Chip/SoC specific files</i>.
Each processor processor architecture is embedded in chip or <i>System-on-a-Chip</i> (SoC) architecture.
The full chip architecture includes the processor architecture plus chip-specific interrupt logic,
clocking logic, general purpose I/O (GIO) logic, and specialized, internal peripherals (such as UARTs, USB, etc.).
<p>
These chip-specific files are contained within chip-specific sub-directories in the
<code>arch/</code><i>&lt;arch-name&gt;</i><code>/</code> directory and are selected via
the <code>CONFIG_ARCH_name</code> selection.
</p>
</li>
<li>
<i>Board specific files</i>.
In order to be usable, the chip must be contained in a board environment.
The board configuration defines additional properties of the board including such things as
peripheral LEDs, external peripherals (such as network, USB, etc.).
<p>
These board-specific configuration files can be found in the
<code>configs/</code><i>&lt;board-name&gt;</i><code>/</code> sub-directories and are discussed
in a a paragraph <a href="#configsdirectorystructure">below</a>.
</p>
</li>
</ul>
<h2>2.1 <a name="DirStructDocumentation">Documentation</a></h2>
<p>
@@ -168,23 +223,33 @@ below and discussed in the following paragraphs:</p>
The complete board port in is defined by the architecture-specific code in this
directory (plus the board-specific configurations in the <code>config/</code>
subdirectory).
Each architecture must provide a subdirectory, &lt;<i>arch-name</i>&gt;
Each architecture must provide a subdirectory, <i>&lt;arch-name&gt;</i>
under <code>arch/</code> with the following characteristics:
</p>
<ul><pre>
&lt;<i>arch-name</i>&gt;
<i>&lt;arch-name&gt;</i>/
|-- include/
| |--<i>&lt;chip-name&gt;</i>/
| | `-- <i>(chip-specific header files)</i>
| |--<i>&lt;other-chips&gt;</i>/
| |-- arch.h
| |-- irq.h
| |-- types.h
| `-- limits.h
`-- src/
|--<i>&lt;chip-name&gt;</i>/
| `-- <i>(chip-specific source files)</i>
|--<i>&lt;other-chips&gt;</i>/
|-- Makefile
`-- <i>(architecture-specific source files)</i>
</pre></ul>
<h3><a name="summaryofarchfiles">2.2.2 Summary of Files</a></h3>
<ul>
<li>
<code>include/</code><i>&lt;chip-name&gt;</i><code>/</code>
This sub-directory contains chip-specific header files.
</li>
<li>
<code>include/arch.h</code>:
This is a hook for any architecture specific definitions that may
@@ -239,6 +304,10 @@ below and discussed in the following paragraphs:</p>
by the board.
</p>
</li>
<li>
<code>src/</code><i>&lt;chip-name&gt;</i><code>/</code>
This sub-directory contains chip-specific source files.
</li>
<li>
<code>src/Makefile</code>:
This makefile will be executed to build the targets <code>src/libup.a</code> and
@@ -251,7 +320,7 @@ below and discussed in the following paragraphs:</p>
<i>(architecture-specific source files)</i>.
The file <code>include/nuttx/arch.h</code> identifies all of the APIs that must
be provided by the architecture specific logic. (It also includes
<code>arch/&lt;arch-name&gt;/arch.h</code> as described above).
<code>arch/</code><i>&lt;arch-name&gt;</i><code>/arch.h</code> as described above).
</li>
</ul>
@@ -293,29 +362,32 @@ below and discussed in the following paragraphs:</p>
provide a subdirectory &lt;board-name&gt; under <code>configs/</code> with the following characteristics:
</p>
<ul><pre>
&lt;<i>board-name</i>&gt;
<i>&lt;board-name&gt;</i>
|-- include/
| `-- <i>(board-specific header files)</i>
|-- src/
| `-- Makefile
| |-- Makefile
| `-- <i>(board-specific source files)</i>
|-- Make.defs
|-- defconfig
`-- setenv.sh
</pre></ul>
<h3><a name="#summaryofconfigfiles">2.3.2 Summary of Files</a></h3>
<h3><a name="summaryofconfigfiles">2.3.2 Summary of Files</a></h3>
<h4><a name="boardlogic">2.3.2.1 Board Specific Logic</a></h4>
<ul>
<li>
<code>include/</code>:
This directory contains board specific header files.
This directory will be linked as <code>include/arch/board</code> at configuration time
and can be included via <code>#include &lt;arch/board/header.h&gt;</code>.
These header file can only be included by files in <code>arch/&lt;arch-name&gt;/include/</code>
and <code>arch/&lt;arch-name&gt;/src/</code>.
These header file can only be included by files in <code>arch/</code><i>&lt;arch-name&gt;</i><code>/include/</code>
and <code>arch/</code><i>&lt;arch-name&gt;</i><code>/src/</code>.
</li>
<li>
<code>src/</code>:
This directory contains board specific drivers.
This directory will be linked as <config>arch/&lt;arch-name&gt;/src/board</config> at configuration
This directory will be linked as <config>arch/</code><i>&lt;arch-name&gt;</i><code>/src/board</config> at configuration
time and will be integrated into the build system.
</li>
<li>
@@ -323,6 +395,15 @@ below and discussed in the following paragraphs:</p>
This makefile will be invoked to build the board specific drivers.
It must support the following targets: <code>libext$(LIBEXT)</code>, <code>clean</code>, and <code>distclean</code>.
</li>
</ul>
<h4><a name="boardconfigfiles">2.3.2.2 Board Specific Configuration Files</a></h4>
<p>
The <code>configs/</code><i>&lt;board-name&gt;</i><code>/</code> sub-directory holds all of the
files that are necessary to configure Nuttx for the particular board.
The procedure for configuring NuttX is described <a href="#configuringnuttx">below</a>,
This paragraph will describe the contents of these configuration files.
</p>
<ul>
<li>
<code>Make.defs</code>: This makefile fragment provides architecture and
tool-specific build options. It will be included by all other
@@ -362,7 +443,12 @@ below and discussed in the following paragraphs:</p>
</li>
</ul>
<h3><a name="#supportedboards">2.3.3 Supported Boards</a></h3>
<h3><a name="supportedboards">2.3.3 Supported Boards</a></h3>
<p>
All of the specific boards supported by NuttX are identified below.
These the the specific <i>&lt;board-name&gt;</i>'s that may be used to configure NuttX
as described <a href="#configuringnuttx">below</a>.
</p>
<ul>
<li><code>configs/sim</code>:
A user-mode port of NuttX to the x86 Linux platform is available.
@@ -399,24 +485,6 @@ below and discussed in the following paragraphs:</p>
is available to build these toolchains.
</blockquote></small></p>
<h3><a name="configuringnuttx">2.3.4 Configuring NuttX</a></h3>
<p>
Configuring NuttX requires only copying:
</p>
<ul>
<code>configs/&lt;<i>board-name</i>&gt;/Make.def</code> to <code>${TOPDIR}/Make.defs</code>,
<code>configs/&lt;<i>board-name</i>&gt;/setenv.sh</code> to <code>${TOPDIR}/setenv.sh</code>, and
<code>configs/&lt;<i>board-name</i>&gt;/defconfig</code> to ${TOPDIR}/.config</code>
</ul>
<p>
There is a script that automates these steps. The following steps will
accomplish the same configuration:
</p>
<ul><pre>
cd tools
./configure.sh &lt;<i>board-name</i>&gt;
</pre></ul>
<h2>2.4 <a name="DirStructDrivers">drivers</a></h2>
<p>
@@ -453,33 +521,112 @@ below and discussed in the following paragraphs:</p>
</ul>
<h2>2.8 <a name="DirStructLib">lib</a></h2>
<p>
This directory holds a collection of standard libc-like functions with custom
interfaces into Nuttx.
</p>
<h2>2.9 <a name="DirStructMm">mm</a></h2>
<p>
This is the NuttX memory manager.
</p>
<h2>2.10 <a name="DirStructSched">sched</a></h2>
<p>
The files forming core of the NuttX RTOS reside here.
</p>
<h2>2.11 <a name="DirStructTools">tools</a></h2>
<p>
This directory holds a collection of tools and scripts to simplify
configuring and building NuttX.
</p>
<h2>2.12 <a name="topmakefile">Makefile</a></h2>
<p>
The top-level <code>Makefile</code> in the <code>${TOPDIR}</code> directory contains all of the top-level control
logic to build NuttX.
Use of this <code>Makefile</code> to build NuttX is described <a href="#buildingnuttx">below</a>.
</p>
<hr>
<h1>3.0 <a name="DirectoryConfiAndBuild">Configuring and Building</a></h1>
<h1>3.0 <a name="configandbuild">Configuring and Building</a></h1>
<h2><a name="configuringnuttx">3.1 Configuring NuttX</a></h2>
<p>
<b>Manual Configuration</b>.
Configuring NuttX requires only copying the
<a href="#boardconfigfiles">board-specific configuration files</a> into the top level directory which appears in the make files as the make variable, <code>${TOPDIR}</code>.
This could be done manually as follows:
</p>
<ul>
<li>Copy <code>configs/</code><i>&lt;board-name&gt;</i></code>/Make.def</code> to <code>${TOPDIR}/Make.defs</code>,<li>
<li>Copy <code>configs/</code><i>&lt;board-name&gt;</i></code>/setenv.sh</code> to <code>${TOPDIR}/setenv.sh</code>, and</li>
<li>Copy <code>configs/</code><i>&lt;board-name&gt;</i></code>/defconfig</code> to <code>${TOPDIR}/.config</code></li>
</ul>
<p>
Where <i>&lt;board-name&gt;</i> is the name of one of the sub-directories of the
NuttX <a href="#DirStructConfigs"><code>configs/</code></a> directory.
This sub-directory name corresponds to one of the supported boards
identified <a href="#supportedboards">above</a>.
</p>
<p>
<b>Automated Configuration</b>.
There is a script that automates these steps. The following steps will
accomplish the same configuration:
</p>
<ul><pre>
cd tools
./configure.sh <i>&lt;board-name&gt;</i>
</pre></ul>
<p>
<b>Additional Configuration Steps</b>.
The remainder of configuration steps will be performed by <a href="#topmakefile"><code>${TOPDIR}/Makefile</code></a>
the first time the system is built as described below.
</p>
<h2><a name="buildingnuttx">3.2 Building NuttX</a></h2>
<p>
<b>Building NuttX</b>.
Once NuttX has been configured as described <a href="#configuringnuttx">above</a>, it may be built as follows:
</p>
<ul><pre>
cd ${TOPDIR}
source ./setenv.sh
make
</pre></ul>
<p>
The <code>${TOPDIR}</code> directory holds:
</p>
<ul>
<li>The top level <a href="#topmakefile"><code>Makefile</code></a> that controls the NuttX build.
</ul>
<p>
That directory also holds:
</p>
<ul>
<li>The makefile fragment <a href="#boardconfigfiles"><code>.config</code></a> that describes the current configuration.</li>
<li>The makefile fragment <a href="#boardconfigfiles"><code>Make.defs</code></a> that provides customized build targers, and</li>
<li>The shell script <a href="#boardconfigfiles"><code>setenv.sh</code></a> that sets up the configuration environment for the build.</li>
</ul>
<p>
The <a href="#boardconfigfiles"><code>setenv.sh</code></a> contains Linux environmental settings that are needed for the build.
The specific environmental definitions are unique for each board but should include, as a minimum, updates to the <code>PATH</code> variable to include the full path to the architecture-specific toolchain identified in <a href="#boardconfigfiles"><code>Make.defs</code></a>.
The <a href="#boardconfigfiles"><code>setenv.sh</code></a> only needs to be source'ed at the beginning of a session.
The system can be re-made subsequently by just typing <code>make</code>.
</p>
<p>
<b>First Time Make.</b>
Additional configuration actions will be taken the first time that system is built.
These additional steps include:
</p>
<ul>
<li>Auto-generating the file <code>include/nuttx/config.</code> using the <code>${TOPDIR}/.config</code> file.
<li>Creating a link to <code>${TOPDIR}/arch/</code><i>&lt;arch-name&gt;</i><code>/include</code> at <code>${TOPDIR}/include/arch</code>.
<li>Creating a link to <code>${TOPDIR}/configs/</code><i>&lt;board-name&gt;</i><code>/include</code> at <code>${TOPDIR}/include/arch/board</code>.
<li>Creating a link to <code>${TOPDIR}/configs/</code><i>&lt;board-name&gt;</i><code>/src</code> at <code>${TOPDIR}/arch/</code><i>&lt;arch-name&gt;</i><code>/src/board</code>
<li>Creating make dependencies.
</ul>
<h1>4.0 <a name="ArchAPIs">Architecture APIs</a></h1>

File diff suppressed because it is too large Load Diff

View File

@@ -1,18 +1,18 @@
Nuttx-0.2.2
nuttx-0.2.3
^^^^^^^^^^^^
This is the fifth release of NuttX. There is no major new
functionality in this release. This release adds support for
new pthread barrier APIs, changes the directory structure,
to better handle different board configuarations using the same
processor architecture, and corrects a defect defects.
This is the sixth release of NuttX. This release is primarily
a bugfix release. Numerous problems were fixed as detailed
in the change log. New functionaliy includes support for
timed messsage queues.
See the ChangeLog for a complete list of changes.
This release has been verified on the Linux user-mode platform and
the Neuros OSD using the test program under examples/ostest.
There are no known, critical defects but the project development
status remains at 'beta' status pending further test and
evaluation.
This release has been verified on the Linux user-mode platform
and the Neuros OSD using the test program under examples/ostest.
The results of the testing is available in the source tree under
configs/ntosd-dm320/doc/test-results. There are no known,
critical defects but the project development status remains at
'beta' status pending further test and evaluation.
This tarball contains a complete CVS snapshot from March 26, 2007.
This tarball contains a complete CVS snapshot from March 29, 2007.

20
TODO
View File

@@ -1,9 +1,7 @@
NuttX TODO List
^^^^^^^^^^^^^^^
Task/Scheduler
^^^^^^^^^^^^^^
o Task/Scheduler
- When a tasks exits, shouldn't all of its child pthreads also be terminated?
- Should task_delete() cause atexit() function to be called?
- Implement sys/mman.h and functions
@@ -27,16 +25,6 @@ o pthreads
- pthread_cancel(): Should implemenent cancellation points and pthread_testcancel()
o Libraries
- There seems to be some kind of failure in the mutual exclusion logic on
buffered, "standard," IO.
- If two threads try fflush-ing at the same time, there is corruption
of the output.
- Yhere is a failure in the examples/ostest POSIX timer
test when CONFIG_DEBUG is enabled. This is almost certainly yet
another case where printf (or its kin) are being called from a
sensitive area in the OS.
- I am now seeing the same thing with the dm320 barrier test.
Apparently printf has some thread safety issues.
o File system
- Add some concept like mount points to handle mounted "real" filesystems.
@@ -44,8 +32,8 @@ o File system
o Console Output
o Documentation
- Document fs & driver logic
- Document filesystem, library
- Document fs/ & driver/ logic
- Document C-library APIs
o Build system
- Names under arch are incorrect. These should hold processor architectures.
@@ -63,7 +51,7 @@ o C5471
o DM320
o pjrc-8052 / MCS51
* Current status:
- Current status:
- Basic OS task management seems OK
- Fails when interrupts enabled. The stack pointer is around 0x6e
before the failure occurs. It looks like some issue when the

View File

@@ -11,8 +11,33 @@ Table of Contents
Architecture-Specific Code
^^^^^^^^^^^^^^^^^^^^^^^^^^
The file include/nuttx/arch.h identifies all of the APIs that must
be provided by the architecture specific logic. (It also includes
The NuttX configuration consists of:
o Processor architecture specific files. These are the files contained
in the arch/<arch-name>/ directory discussed in this README.
o Chip/SoC specific files. Each processor processor architecture
is embedded in chip or System-on-a-Chip (SoC) architecture. The
full chip architecture includes the processor architecture plus
chip-specific interrupt logic, general purpose I/O (GIO) logic, and
specialized, internal peripherals (such as UARTs, USB, etc.).
These chip-specific files are contained within chip-specific
sub-directories in the arch/<arch-name>/ directory and are selected
via the CONFIG_ARCH_name selection
o Board specific files. In order to be usable, the chip must be
contained in a board environment. The board configuration defines
additional properties of the board including such things as
peripheral LEDs, external peripherals (such as network, USB, etc.).
These board-specific configuration files can be found in the
configs/<board-name>/ sub-directories.
This README will address the processor architecture specific files
that are contained in the arch/<arch-name>/ directory. The file
include/nuttx/arch.h identifies all of the APIs that must
be provided by this architecture specific logic. (It also includes
arch/<arch-name>/arch.h as described below).
Directory Structure
@@ -25,18 +50,27 @@ subdirectory). Each architecture must provide a subdirectory <arch-name>
under arch/ with the following characteristics:
<arch-name>
|-- include
<arch-name>/
|-- include/
| |--<chip-name>/
| | `-- (chip-specific header files)
| |--<other-chips>/
| |-- arch.h
| |-- irq.h
| `-- types.h
`-- src
`-- src/
|--<chip-name>/
| `-- (chip-specific source files)
|--<other-chips>/
|-- Makefile
`-- (architecture-specific source files)
Summary of Files
^^^^^^^^^^^^^^^^
include/<chip-name>/
This sub-directory contains chip-specific header files.
include/arch.h
This is a hook for any architecture specific definitions that may
be needed by the system. It is included by include/nuttx/arch.h
@@ -76,6 +110,9 @@ include/irq.h
This file must also define NR_IRQS, the total number of IRQs supported
by the board.
src/<chip-name>/
This sub-directory contains chip-specific source files.
src/Makefile
This makefile will be executed to build the targets src/libup.a and
src/up_head.o. The up_head.o file holds the entry point into the system

View File

@@ -145,6 +145,13 @@ void _exit(int status)
(void)sched_removereadytorun(tcb);
/* We are not in a bad stack-- the head of the ready to run task list
* does not correspond to the thread that is running. Disabling pre-
* emption on this TCB should be enough to keep things stable.
*/
sched_lock();
/* Move the TCB to the specified blocked task list and delete it */
sched_addblocked(tcb, TSTATE_TASK_INACTIVE);
@@ -159,6 +166,10 @@ void _exit(int status)
(void)sched_mergepending();
}
/* Now calling sched_unlock() should have no effect */
sched_unlock();
/* Now, perform the context switch to the new ready-to-run task at the
* head of the list.
*/

View File

@@ -149,6 +149,13 @@ void _exit(int status)
(void)sched_removereadytorun(tcb);
/* We are not in a bad stack-- the head of the ready to run task list
* does not correspond to the thread that is running. Disabling pre-
* emption on this TCB should be enough to keep things stable.
*/
sched_lock();
/* Move the TCB to the specified blocked task list and delete it */
sched_addblocked(tcb, TSTATE_TASK_INACTIVE);
@@ -163,6 +170,10 @@ void _exit(int status)
(void)sched_mergepending();
}
/* Now calling sched_unlock() should have no effect */
sched_unlock();
/* Now, perform the context switch to the new ready-to-run task at the
* head of the list.
*/

View File

@@ -90,6 +90,13 @@ void _exit(int status)
(void)sched_removereadytorun(tcb);
/* We are not in a bad stack-- the head of the ready to run task list
* does not correspond to the thread that is running. Disabling pre-
* emption on this TCB should be enough to keep things stable.
*/
sched_lock();
/* Move the TCB to the specified blocked task list and delete it */
sched_addblocked(tcb, TSTATE_TASK_INACTIVE);
@@ -104,6 +111,10 @@ void _exit(int status)
(void)sched_mergepending();
}
/* Now calling sched_unlock() should have no effect */
sched_unlock();
/* Now, perform the context switch to the new ready-to-run task at the
* head of the list.
*/

View File

@@ -73,6 +73,7 @@
void _exit(int status)
{
_TCB* tcb = (_TCB*)g_readytorun.head;
irqstate_t flags;
dbg("TCB=%p exitting\n", tcb);
@@ -83,13 +84,20 @@ void _exit(int status)
(void)sched_removereadytorun(tcb);
/* We are not in a bad stack-- the head of the ready to run task list
* does not correspond to the thread that is running. Disabling pre-
* emption on this TCB should be enough to keep things stable.
*/
sched_lock();
/* Move the TCB to the specified blocked task list and delete it */
sched_addblocked(tcb, TSTATE_TASK_INACTIVE);
task_delete(tcb->pid);
/* If there are any pending tasks, then add them to the g_readytorun
* task list now
* task list now.
*/
if (g_pendingtasks.head)
@@ -97,6 +105,10 @@ void _exit(int status)
(void)sched_mergepending();
}
/* Now calling sched_unlock() should have no effect */
sched_unlock();
/* Now, perform the context switch to the new ready-to-run task at the
* head of the list.
*/

View File

@@ -11,9 +11,33 @@ Table of Contents
Board-Specific Configurations
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The NuttX configuration consists of:
o Processor architecture specific files. These are the files contained
in the arch/<arch-name>/ directory.
o Chip/SoC specific files. Each processor processor architecture
is embedded in chip or System-on-a-Chip (SoC) architecture. The
full chip architecture includes the processor architecture plus
chip-specific interrupt logic, general purpose I/O (GIO) logic, and
specialized, internal peripherals (such as UARTs, USB, etc.).
These chip-specific files are contained within chip-specific
sub-directories in the arch/<arch-name>/ directory and are selected
via the CONFIG_ARCH_name selection
o Board specific files. In order to be usable, the chip must be
contained in a board environment. The board configuration defines
additional properties of the board including such things as
peripheral LEDs, external peripherals (such as network, USB, etc.).
These board-specific configuration files can be found in the
configs/<board-name>/ sub-directories and are discussed in this
README.
The configs/ subdirectory contains configuration data for each board. These
board-specific configurations plus the architecture-specific configurations in
the arch/ subdirectory complete define a customized port of NuttX.
the arch/ subdirectory completely define a customized port of NuttX.
Directory Structure
^^^^^^^^^^^^^^^^^^^
@@ -25,8 +49,10 @@ following characteristics:
<board-name>
|-- include/
| `-- (board-specific header files)
|-- src/
| `-- Makefile
| |-- Makefile
| `-- (board-specific source files)
|-- Make.defs
|-- defconfig
`-- setenv.sh

View File

@@ -1,7 +1,17 @@
This is the output from running examples/ostest on March 23, 2007
This is the output from running examples/ostest on March 28, 2007
=================================================================
go 1008000
Neuros Devboard > tftpboot 10.0.0.1 nuttx.dm320
Found DM9000 ID:90000a46 at address 60000300 !
DM9000 work in 16 bus width
[eth_init]MAC:0:18:11:80:10:6:
TFTP from server 10.0.0.1; our IP address is 10.0.0.2
Filename 'nuttx.dm320'.
Load address: 0x10
Loading: #############################
done
Bytes transferred = 146570 (23c8a hex)
Neuros Devboard > go 1008000
## Starting application at 0x01008000 ...
stdio_test: write fd=1
stdio_test: write fd=2
@@ -20,11 +30,11 @@ user_main: argv[4]="Arg4"
End of test memory usage:
VARIABLE BEFORE AFTER
======== ======== ========
arena fe1f10 fe1f10
arena fe0f10 fe0f10
ordblks 2 2
mxordblk fda9b0 fda9b0
mxordblk fd99b0 fd99b0
uordblks 53f0 53f0
fordblks fdcb20 fdcb20
fordblks fdbb20 fdbb20
user_main: /dev/null test
dev_null: Read 0 bytes from /dev/null
@@ -33,28 +43,28 @@ dev_null: Wrote 1024 bytes to /dev/null
End of test memory usage:
VARIABLE BEFORE AFTER
======== ======== ========
arena fe1f10 fe1f10
arena fe0f10 fe0f10
ordblks 2 2
mxordblk fda9b0 fda9b0
mxordblk fd99b0 fd99b0
uordblks 53f0 53f0
fordblks fdcb20 fdcb20
fordblks fdbb20 fdbb20
user_main: mutex test
Initializing mutex
Starting thread 1
Starting thread 2
Thread1 Thread2
Loops 32 32
Errors 0 0
Thread1 Thread2
Loops 32 32
Errors 0 0
End of test memory usage:
VARIABLE BEFORE AFTER
======== ======== ========
arena fe1f10 fe1f10
arena fe0f10 fe0f10
ordblks 2 2
mxordblk fda9b0 fda9b0
mxordblk fd99b0 fd99b0
uordblks 53f0 53f0
fordblks fdcb20 fdcb20
fordblks fdbb20 fdbb20
user_main: cancel test
cancel_test: Test 1: Normal Cancelation
@@ -105,11 +115,11 @@ cancel_test: PASS thread terminated with PTHREAD_CANCELED
End of test memory usage:
VARIABLE BEFORE AFTER
======== ======== ========
arena fe1f10 fe1f10
arena fe0f10 fe0f10
ordblks 2 2
mxordblk fda9b0 fda9b0
mxordblk fd99b0 fd99b0
uordblks 53f0 53f0
fordblks fdcb20 fdcb20
fordblks fdbb20 fdbb20
user_main: semaphore test
sem_test: Initializing semaphore to 0
@@ -117,8 +127,8 @@ sem_test: Starting waiter thread 1
sem_test: Set thread 1 priority to 191
waiter_func: Thread 1 Started
waiter_func: Thread 1 initial semaphore value = 0
waiter_func: sThread 1 aiting on semaphore
em_test: Starting waiter thread 2
waiter_func: Thread 1 aiting on semaphore
sem_test: Starting waiter thread 2
sem_test: Set thread 2 priority to 128
waiter_func: Thread 2 Started
waiter_func: Thread 2 initial semaphore value = -1
@@ -143,11 +153,11 @@ poster_func: Thread 3 done
End of test memory usage:
VARIABLE BEFORE AFTER
======== ======== ========
arena fe1f10 fe1f10
arena fe0f10 fe0f10
ordblks 2 2
mxordblk fda9b0 fda9b0
mxordblk fd99b0 fd99b0
uordblks 53f0 53f0
fordblks fdcb20 fdcb20
fordblks fdbb20 fdbb20
user_main: condition variable test
cond_test: Initializing mutex
@@ -160,10 +170,10 @@ cond_test: Set thread 2 priority to 64
thread_signaler: Started
thread_signaler: Terminating
cond_test: signaler terminated, now cancel the waiter
cond_test: Waiter Signaler
cond_test: Loops 32 32
cond_test: Errors 0 0
cond_test:
cond_test: Waiter Signaler
cond_test: Loops 32 32
cond_test: Errors 0 0
cond_test:
0 times, waiter did not have to wait for data
cond_test: 0 times, data was already available when the signaler run
cond_test: 0 times, the waiter was in an unexpected state when the signaler ran
@@ -171,11 +181,11 @@ cond_test: 0 times, the waiter was in an unexpected state when the signaler ran
End of test memory usage:
VARIABLE BEFORE AFTER
======== ======== ========
arena fe1f10 fe1f10
arena fe0f10 fe0f10
ordblks 2 2
mxordblk fda9b0 fda9b0
mxordblk fd99b0 fd99b0
uordblks 53f0 53f0
fordblks fdcb20 fdcb20
fordblks fdbb20 fdbb20
user_main: timed wait test
thread_waiter: Initializing mutex
@@ -193,11 +203,11 @@ timedwait_test: waiter exited with result=12345678
End of test memory usage:
VARIABLE BEFORE AFTER
======== ======== ========
arena fe1f10 fe1f10
arena fe0f10 fe0f10
ordblks 2 2
mxordblk fda9b0 fda9b0
mxordblk fd99b0 fd99b0
uordblks 53f0 53f0
fordblks fdcb20 fdcb20
fordblks fdbb20 fdbb20
user_main: message queue test
mqueue_test: Starting receiver
@@ -215,8 +225,8 @@ receiver_thread: mq_receive succeeded on msg 2
sender_thread: mq_send succeeded on msg 2
receiver_thread: mq_receive succeeded on msg 3
sender_thread: mq_send succeeded on msg 3
receivers_thread: mq_receive succeeded on msg 4
ender_thread: mq_send succeeded on msg 4
receiver_thread: mq_receive succeeded on msg 4
sender_thread: mq_send succeeded on msg 4
receiver_thread: mq_receive succeeded on msg 5
sender_thread: mq_send succeeded on msg 5
receiver_thread: mq_receive succeeded on msg 6
@@ -226,30 +236,73 @@ sender_thread: mq_send succeeded on msg 7
receiver_thread: mq_receive succeeded on msg 8
sender_thread: mq_send succeeded on msg 8
receiver_thread: mq_receive succeeded on msg 9
receiver_thread: returning nerrors=0
sender_thread: mq_send succeeded on msg 9
sender_thread: returning nerrors=0
mqueue_test: Killing receiver
receiver_thread: mq_receive interrupted!
receiver_thread: returning nerrors=0
mqueue_test: Canceling receiver
mqueue_test: receiver has already terminated
End of test memory usage:
VARIABLE BEFORE AFTER
======== ======== ========
arena fe1f10 fe1f10
arena fe0f10 fe0f10
ordblks 2 2
mxordblk fda9b0 fda9b0
mxordblk fd99b0 fd99b0
uordblks 53f0 53f0
fordblks fdcb20 fdcb20
fordblks fdbb20 fdbb20
user_main: timed message queue test
timedmqueue_test: Starting sender
sender_thread: Starting
sender_thread: mq_timedsend succeeded on msg 0
sender_thread: mq_timedsend succeeded on msg 1
sender_thread: mq_timedsend succeeded on msg 2
sender_thread: mq_timedsend succeeded on msg 3
sender_thread: mq_timedsend succeeded on msg 4
sender_thread: mq_timedsend succeeded on msg 5
sender_thread: mq_timedsend succeeded on msg 6
sender_thread: mq_timedsend succeeded on msg 7
sender_thread: mq_timedsend succeeded on msg 8
timedmqueue_test: Waiting for sender to complete
sender_thread: mq_timedsend 9 timed out as expected
sender_thread: returning nerrors=0
timedmqueue_test: Starting receiver
receiver_thread: Starting
receiver_thread: mq_timedreceive succeeded on msg 0
receiver_thread: mq_timedreceive succeeded on msg 1
receiver_thread: mq_timedreceive succeeded on msg 2
receiver_thread: mq_timedreceive succeeded on msg 3
receiver_thread: mq_timedreceive succeeded on msg 4
receiver_thread: mq_timedreceive succeeded on msg 5
receiver_thread: mq_timedreceive succeeded on msg 6
receiver_thread: mq_timedreceive succeeded on msg 7
receiver_thread: mq_timedreceive succeeded on msg 8
timedmqueue_test: Waiting for sender to complete
receiver_thread: Receive 9 timed out as expected
receiver_thread: returning nerrors=0
timedmqueue_test: Test complete
End of test memory usage:
VARIABLE BEFORE AFTER
======== ======== ========
arena fe0f10 fe0f10
ordblks 2 2
mxordblk fd99b0 fd99b0
uordblks 53f0 53f0
fordblks fdbb20 fdbb20
user_main: signal handler test
sighand_test: Initializing semaphore to 0
sighand_test: Starting waiter task
sighand_test: Started waiter_main pid=16
sighand_test: Started waiter_main pid=18
waiter_main: Waiter started
waiter_main: Unmasking signal 17
waiter_main: Registering signal handler
waiter_main: oact.sigaction=0 oact.sa_flags=0 oact.sa_mask=0
waiter_main: Waiting on semaphore
sighand_test: Signaling pid=16 with signo=17 sigvalue=42
sighand_test: Signaling pid=18 with signo=17 sigvalue=42
wakeup_action: Received signal 17
wakeup_action: sival_int=42
wakeup_action: si_code=1
@@ -261,11 +314,11 @@ sighand_test: done
End of test memory usage:
VARIABLE BEFORE AFTER
======== ======== ========
arena fe1f10 fe1f10
arena fe0f10 fe0f10
ordblks 2 2
mxordblk fda9b0 fda9b0
mxordblk fd99b0 fd99b0
uordblks 53f0 53f0
fordblks fdcb20 fdcb20
fordblks fdbb20 fdbb20
user_main: POSIX timer test
timer_test: Initializing semaphore to 0
@@ -315,17 +368,17 @@ timer_test: done
End of test memory usage:
VARIABLE BEFORE AFTER
======== ======== ========
arena fe1f10 fe1f10
arena fe0f10 fe0f10
ordblks 2 2
mxordblk fda9b0 fda9b0
mxordblk fd99b0 fd99b0
uordblks 53f0 53f0
fordblks fdcb20 fdcb20
fordblks fdbb20 fdbb20
user_main: round-robin scheduler test
rr_test: Starting sieve1 thread
rr_test: Starting sieve1 thread
rr_test: Set thread priority to 1
rr_test: Set thread policty to SCHED_RR
rr_test: Starting sieve1 thread
rr_test: Starting sieve1 thread
sieve1 started
sieve1 finished
rr_test: Waiting for sieves to complete -- this should take awhile
@@ -338,18 +391,78 @@ rr_test: Done
End of test memory usage:
VARIABLE BEFORE AFTER
======== ======== ========
arena fe1f10 fe1f10
arena fe0f10 fe0f10
ordblks 2 2
mxordblk fda9b0 fda9b0
mxordblk fd99b0 fd99b0
uordblks 53f0 53f0
fordblks fdcb20 fdcb20
fordblks fdbb20 fdbb20
user_main: barrier test
barrier_test: Initializing barrier
barrier_func: Thread 0 started
barrier_test: Thread 0 created
barrier_func: Thread 1 started
barrier_test: Thread 1 created
barrier_func: Thread 0 calling pthread_barrier_wait()
barrier_func: Thread 1 calling pthread_barrier_wait()
barrier_func: Thread 2 started
barrier_test: Thread 2 created
barrier_func: Thread 3 started
barrier_test: Thread 3 created
barrier_func: Thread 4 started
barrier_test: Thread 4 created
barrier_func: Thread 5 started
barrier_func: Thread 2 calling pthread_barrier_wait()
barrier_func: Thread 3 calling pthread_barrier_wait()
barrier_func: Thread 4 calling pthread_barrier_wait()
barrier_test: Thread 5 created
barrier_func: Thread 6 started
barrier_test: Thread 6 created
barrier_func: Thread 7 started
barrier_test: Thread 7 created
barrier_func: Thread 5 calling pthread_barrier_wait()
barrier_func: Thread 6 calling pthread_barrier_wait()
barrier_func: Thread 7 calling pthread_barrier_wait()
barrier_func: Thread 7, back with status=PTHREAD_BARRIER_SERIAL_THREAD (I AM SPECIAL)
barrier_func: Thread 0, back with status=0 (I am not special)
barrier_func: Thread 1, back with status=0 (I am not special)
barrier_func: Thread 2, back with status=0 (I am not special)
barrier_func: Thread 3, back with status=0 (I am not special)
barrier_func: Thread 4, back with status=0 (I am not special)
barrier_func: Thread 5, back with status=0 (I am not special)
barrier_func: Thread 6, back with status=0 (I am not special)
barrier_func: Thread 7 done
barrier_func: Thread 0 done
barrier_test: Thread 0 completed with result=0
barrier_func: Thread 1 done
barrier_func: Thread 2 done
barrier_func: Thread 3 done
barrier_func: Thread 4 done
barrier_func: Thread 5 done
barrier_func: Thread 6 done
barrier_test: Thread 1 completed with result=0
barrier_test: Thread 2 completed with result=0
barrier_test: Thread 3 completed with result=0
barrier_test: Thread 4 completed with result=0
barrier_test: Thread 5 completed with result=0
barrier_test: Thread 6 completed with result=0
barrier_test: Thread 7 completed with result=0
End of test memory usage:
VARIABLE BEFORE AFTER
======== ======== ========
arena fe0f10 fe0f10
ordblks 2 2
mxordblk fd99b0 fd99b0
uordblks 53f0 53f0
fordblks fdbb20 fdbb20
Final memory usage:
VARIABLE BEFORE AFTER
======== ======== ========
arena fe1f10 fe1f10
arena fe0f10 fe0f10
ordblks 2 2
mxordblk fda9b0 fda9b0
mxordblk fd99b0 fd99b0
uordblks 53f0 53f0
fordblks fdcb20 fdcb20
fordblks fdbb20 fdbb20
user_main: Exitting

View File

@@ -45,15 +45,10 @@
* Definitions
************************************************************/
#define CS2 *(volatile uint32*)0xffff2e08
#define LEDS *(volatile uint32*)0x01000000
/************************************************************
* Private Data
************************************************************/
static uint32 g_ledstate;
/************************************************************
* Private Functions
************************************************************/

View File

@@ -47,12 +47,17 @@ endif
ifneq ($(CONFIG_DISABLE_SIGNALS),y)
CSRCS += sighand.c
ifneq ($(CONFIG_DISABLE_PTHREAD),y)
ifneq ($(CONFIG_DISABLE_CLOCK),y)
CSRCS += timedwait.c
endif
endif
endif
ifneq ($(CONFIG_DISABLE_MQUEUE),y)
ifneq ($(CONFIG_DISABLE_PTHREAD),y)
CSRCS += mqueue.c
ifneq ($(CONFIG_DISABLE_CLOCK),y)
CSRCS += timedmqueue.c
endif
endif
endif
ifneq ($(CONFIG_DISABLE_POSIX_TIMERS),y)

View File

@@ -237,7 +237,7 @@ static int user_main(int argc, char *argv[])
check_test_memory_usage();
#endif
#if !defined(CONFIG_DISABLE_SIGNALS) && !defined(CONFIG_DISABLE_PTHREAD)
#if !defined(CONFIG_DISABLE_SIGNALS) && !defined(CONFIG_DISABLE_PTHREAD) && !defined(CONFIG_DISABLE_CLOCK)
/* Verify pthreads and condition variable timed waits */
printf("\nuser_main: timed wait test\n");
@@ -253,6 +253,14 @@ static int user_main(int argc, char *argv[])
check_test_memory_usage();
#endif
#if !defined(CONFIG_DISABLE_MQUEUE) && !defined(CONFIG_DISABLE_PTHREAD) && !defined(CONFIG_DISABLE_CLOCK)
/* Verify pthreads and message queues */
printf("\nuser_main: timed message queue test\n");
timedmqueue_test();
check_test_memory_usage();
#endif
#ifndef CONFIG_DISABLE_SIGNALS
/* Verify signal handlers */

View File

@@ -37,13 +37,17 @@
* Included Files
**************************************************************************/
#include <nuttx/config.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <pthread.h>
#include <mqueue.h>
#include <sched.h>
#include <errno.h>
#include "ostest.h"
@@ -51,11 +55,18 @@
* Private Definitions
**************************************************************************/
#define TEST_MESSAGE "This is a test and only a test"
#define TEST_MESSAGE "This is a test and only a test"
#ifdef SDCC
#define TEST_MSGLEN (31)
#define TEST_MSGLEN (31)
#else
#define TEST_MSGLEN (strlen(TEST_MESSAGE)+1)
#define TEST_MSGLEN (strlen(TEST_MESSAGE)+1)
#endif
#define TEST_SEND_NMSGS (10)
#ifndef CONFIG_DISABLE_SIGNALS
# define TEST_RECEIVE_NMSGS (11)
#else
# define TEST_RECEIVE_NMSGS (10)
#endif
/**************************************************************************
@@ -121,9 +132,9 @@ static void *sender_thread(void *arg)
memcpy(msg_buffer, TEST_MESSAGE, TEST_MSGLEN);
/* Perform the send 10 times */
/* Perform the send TEST_SEND_NMSGS times */
for (i = 0; i < 10; i++)
for (i = 0; i < TEST_SEND_NMSGS; i++)
{
status = mq_send(mqfd, msg_buffer, TEST_MSGLEN, 42);
if (status < 0)
@@ -183,16 +194,27 @@ static void *receiver_thread(void *arg)
pthread_exit((pthread_addr_t)1);
}
/* Perform the receive 10 times */
/* Perform the receive TEST_RECEIVE_NMSGS times */
for (i = 0; i < 10; i++)
for (i = 0; i < TEST_RECEIVE_NMSGS; i++)
{
memset(msg_buffer, 0xaa, TEST_MSGLEN);
nbytes = mq_receive(mqfd, msg_buffer, TEST_MSGLEN, 0);
if (nbytes < 0)
{
printf("receiver_thread: ERROR mq_receive failure on msg %d\n", i);
nerrors++;
/* mq_receive failed. If the error is because of EINTR then
* it is not a failure.
*/
if (*get_errno_ptr() != EINTR)
{
printf("receiver_thread: ERROR mq_receive failure on msg %d, errno=%d\n", i, *get_errno_ptr());
nerrors++;
}
else
{
printf("receiver_thread: mq_receive interrupted!\n", i);
}
}
else if (nbytes != TEST_MSGLEN)
{
@@ -336,8 +358,26 @@ void mqueue_test(void)
printf("mqueue_test: ERROR sender thread exited with %d errors\n", (int)result);
}
#ifndef CONFIG_DISABLE_SIGNALS
/* Wake up the receiver thread with a signal */
printf("mqueue_test: Killing receiver\n");
pthread_kill(receiver, 9);
#endif
/* Wait a bit to see if the thread exits on its own */
usleep(500*1000);
/* Then cancel the thread and see if it did */
printf("mqueue_test: Canceling receiver\n");
pthread_cancel(receiver);
status = pthread_cancel(receiver);
if (status == ESRCH)
{
printf("mqueue_test: receiver has already terminated\n");
}
pthread_join(receiver, &result);
if (result != (void*)0)
{

View File

@@ -76,10 +76,14 @@ extern void sem_test(void);
extern void cond_test(void);
/* queue.c **************************************************/
/* mqueue.c *************************************************/
extern void mqueue_test(void);
/* timedmqueue.c ********************************************/
extern void timedmqueue_test(void);
/* cancel.c *************************************************/
extern void cancel_test(void);

View File

@@ -0,0 +1,384 @@
/**************************************************************************
* mqueue.c
*
* Copyright (C) 2007 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
*
* 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 Gregory Nutt 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 COPYRIGHT HOLDERS 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
* COPYRIGHT OWNER 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.
*
**************************************************************************/
/**************************************************************************
* Included Files
**************************************************************************/
#include <nuttx/config.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <pthread.h>
#include <mqueue.h>
#include <sched.h>
#include <errno.h>
#include "ostest.h"
/**************************************************************************
* Private Definitions
**************************************************************************/
#define TEST_MESSAGE "This is a test and only a test"
#ifdef SDCC
#define TEST_MSGLEN (31)
#else
#define TEST_MSGLEN (strlen(TEST_MESSAGE)+1)
#endif
#define TEST_SEND_NMSGS (10)
#define TEST_RECEIVE_NMSGS (10)
/**************************************************************************
* Private Types
**************************************************************************/
/**************************************************************************
* Private Function Prototypes
**************************************************************************/
/**************************************************************************
* Global Variables
**************************************************************************/
/**************************************************************************
* Private Variables
**************************************************************************/
/**************************************************************************
* Private Functions
**************************************************************************/
/**************************************************************************
* Public Functions
**************************************************************************/
static void *sender_thread(void *arg)
{
mqd_t mqfd;
char msg_buffer[TEST_MSGLEN];
struct mq_attr attr;
int status = 0;
int nerrors = 0;
int i;
printf("sender_thread: Starting\n");
/* Fill in attributes for message queue */
attr.mq_maxmsg = TEST_SEND_NMSGS-1;
attr.mq_msgsize = TEST_MSGLEN;
attr.mq_flags = 0;
/* Set the flags for the open of the queue.
* Make it a blocking open on the queue, meaning it will block if
* this process tries to send to the queue and the queue is full.
*
* O_CREAT - the queue will get created if it does not already exist.
* O_WRONLY - we are only planning to write to the queue.
*
* Open the queue, and create it if the receiving process hasn't
* already created it.
*/
mqfd = mq_open("testmq", O_WRONLY|O_CREAT, 0666, &attr);
if (mqfd < 0)
{
printf("sender_thread: ERROR mq_open failed\n");
pthread_exit((pthread_addr_t)1);
}
/* Fill in a test message buffer to send */
memcpy(msg_buffer, TEST_MESSAGE, TEST_MSGLEN);
/* Perform the send TEST_SEND_NMSGS times */
for (i = 0; i < TEST_SEND_NMSGS; i++)
{
struct timespec time;
status = clock_gettime(CLOCK_REALTIME, &time);
if (status != 0)
{
printf("sender_thread: ERROR clock_gettime failed\n");
}
time.tv_sec += 5;
/* The first TEST_SEND_NMSGS-1 send should succeed. The last
* one should fail with errno == ETIMEDOUT
*/
status = mq_timedsend(mqfd, msg_buffer, TEST_MSGLEN, 42, &time);
if (status < 0)
{
if (i == TEST_SEND_NMSGS-1 && *get_errno_ptr() == ETIMEDOUT)
{
printf("sender_thread: mq_timedsend %d timed out as expected\n", i);
}
else
{
printf("sender_thread: ERROR mq_timedsend failure=%d on msg %d\n", *get_errno_ptr(), i);
nerrors++;
}
}
else
{
if (i == TEST_SEND_NMSGS-1)
{
printf("sender_thread: ERROR mq_timedsend of msg %d succeeded\n", i);
nerrors++;
}
else
{
printf("sender_thread: mq_timedsend succeeded on msg %d\n", i);
}
}
}
/* Close the queue and return success */
if (mq_close(mqfd) < 0)
{
printf("sender_thread: ERROR mq_close failed\n");
}
printf("sender_thread: returning nerrors=%d\n", nerrors);
fflush(stdout);
return (pthread_addr_t)nerrors;
}
static void *receiver_thread(void *arg)
{
mqd_t mqfd;
char msg_buffer[TEST_MSGLEN];
struct mq_attr attr;
int nbytes;
int nerrors = 0;
int i;
printf("receiver_thread: Starting\n");
/* Fill in attributes for message queue */
attr.mq_maxmsg = TEST_SEND_NMSGS-1;
attr.mq_msgsize = TEST_MSGLEN;
attr.mq_flags = 0;
/* Set the flags for the open of the queue.
* Make it a blocking open on the queue, meaning it will block if
* this process tries to* send to the queue and the queue is full.
*
* O_CREAT - the queue will get created if it does not already exist.
* O_RDONLY - we are only planning to write to the queue.
*
* Open the queue, and create it if the sending process hasn't
* already created it.
*/
mqfd = mq_open("testmq", O_RDONLY|O_CREAT, 0666, &attr);
if (mqfd < 0)
{
printf("receiver_thread: ERROR mq_open failed\n");
pthread_exit((pthread_addr_t)1);
}
/* Perform the receive TEST_RECEIVE_NMSGS times */
for (i = 0; i < TEST_RECEIVE_NMSGS; i++)
{
struct timespec time;
int status = clock_gettime(CLOCK_REALTIME, &time);
if (status != 0)
{
printf("sender_thread: ERROR clock_gettime failed\n");
}
time.tv_sec += 5;
/* The first TEST_SEND_NMSGS-1 send should succeed. The last
* one should fail with errno == ETIMEDOUT
*/
memset(msg_buffer, 0xaa, TEST_MSGLEN);
nbytes = mq_timedreceive(mqfd, msg_buffer, TEST_MSGLEN, 0, &time);
if (nbytes < 0)
{
if (i == TEST_SEND_NMSGS-1 && *get_errno_ptr() == ETIMEDOUT)
{
printf("receiver_thread: Receive %d timed out as expected\n", i);
}
else
{
printf("receiver_thread: ERROR mq_timedreceive failure=%d on msg %d\n", *get_errno_ptr(), i);
nerrors++;
}
}
else if (nbytes != TEST_MSGLEN)
{
printf("receiver_thread: mq_timedreceive return bad size %d on msg %d\n", nbytes, i);
nerrors++;
}
else if (memcmp(TEST_MESSAGE, msg_buffer, nbytes) != 0)
{
int j;
printf("receiver_thread: mq_timedreceive returned corrupt message on msg %d\n", i);
printf("receiver_thread: i Expected Received\n");
for (j = 0; j < TEST_MSGLEN-1; j++)
{
if (isprint(msg_buffer[j]))
{
printf("receiver_thread: %2d %02x (%c) %02x (%c)\n",
j, TEST_MESSAGE[j], TEST_MESSAGE[j], msg_buffer[j], msg_buffer[j]);
}
else
{
printf("receiver_thread: %2d %02x (%c) %02x\n",
j, TEST_MESSAGE[j], TEST_MESSAGE[j], msg_buffer[j]);
}
}
printf("receiver_thread: %2d 00 %02x\n",
j, msg_buffer[j]);
}
else if (i == TEST_SEND_NMSGS-1)
{
printf("receiver_thread: ERROR mq_timedreceive of msg %d succeeded\n", i);
nerrors++;
}
else
{
printf("receiver_thread: mq_timedreceive succeeded on msg %d\n", i);
}
}
/* Close the queue and return success */
if (mq_close(mqfd) < 0)
{
printf("receiver_thread: ERROR mq_close failed\n");
nerrors++;
}
/* Destroy the queue */
if (mq_unlink("testmq") < 0)
{
printf("receiver_thread: ERROR mq_close failed\n");
nerrors++;
}
printf("receiver_thread: returning nerrors=%d\n", nerrors);
fflush(stdout);
pthread_exit((pthread_addr_t)nerrors);
return (pthread_addr_t)nerrors;
}
void timedmqueue_test(void)
{
pthread_t sender;
pthread_t receiver;
void *result;
pthread_attr_t attr;
int status;
/* Start the sending thread at the default priority */
printf("timedmqueue_test: Starting sender\n");
status = pthread_attr_init(&attr);
if (status != 0)
{
printf("timedmqueue_test: pthread_attr_init failed, status=%d\n", status);
}
status = pthread_attr_setstacksize(&attr, 16384);
if (status != 0)
{
printf("timedmqueue_test: pthread_attr_setstacksize failed, status=%d\n", status);
}
status = pthread_create(&sender, &attr, sender_thread, NULL);
if (status != 0)
{
printf("timedmqueue_test: pthread_create failed, status=%d\n", status);
}
/* Wait for the sending thread to complete */
printf("timedmqueue_test: Waiting for sender to complete\n");
pthread_join(sender, &result);
if (result != (void*)0)
{
printf("timedmqueue_test: ERROR sender thread exited with %d errors\n", (int)result);
}
/* Start the receiving thread at the default priority */
printf("timedmqueue_test: Starting receiver\n");
status = pthread_attr_init(&attr);
if (status != 0)
{
printf("timedmqueue_test: pthread_attr_init failed, status=%d\n", status);
}
status = pthread_attr_setstacksize(&attr, 16384);
if (status != 0)
{
printf("timedmqueue_test: pthread_attr_setstacksize failed, status=%d\n", status);
}
status = pthread_create(&receiver, &attr, receiver_thread, NULL);
if (status != 0)
{
printf("timedmqueue_test: pthread_create failed, status=%d\n", status);
}
/* Wait for the receiving thread to complete */
printf("timedmqueue_test: Waiting for sender to complete\n");
pthread_join(receiver, &result);
if (result != (void*)0)
{
printf("timedmqueue_test: ERROR receiver thread exited with %d errors\n", (int)result);
}
printf("timedmqueue_test: Test complete\n");
}

View File

@@ -43,6 +43,7 @@
#include <nuttx/config.h>
#include <sys/types.h>
#include <sched.h>
#include <errno.h>
#include <sys/ioctl.h>
#include "fs_internal.h"

View File

@@ -87,12 +87,16 @@ extern "C" {
#define EXTERN extern
#endif
EXTERN mqd_t mq_open(const char *mq_name, int oflags, ... );
EXTERN mqd_t mq_open(const char *mq_name, int oflags, ...);
EXTERN int mq_close(mqd_t mqdes );
EXTERN int mq_unlink(const char *mq_name );
EXTERN int mq_send(mqd_t mqdes, const void *msg, size_t msglen, int prio );
EXTERN int mq_receive(mqd_t mqdes, void *msg, size_t msglen, int *prio );
EXTERN int mq_notify(mqd_t mqdes, const struct sigevent *notification );
EXTERN int mq_unlink(const char *mq_name);
EXTERN int mq_send(mqd_t mqdes, const void *msg, size_t msglen, int prio);
EXTERN int mq_timedsend(mqd_t mqdes, const char *msg, size_t msglen, int prio,
const struct timespec *abstime);
EXTERN ssize_t mq_receive(mqd_t mqdes, void *msg, size_t msglen, int *prio);
EXTERN ssize_t mq_timedreceive(mqd_t mqdes, void *msg, size_t msglen,
int *prio, const struct timespec *abstime);
EXTERN int mq_notify(mqd_t mqdes, const struct sigevent *notification);
EXTERN int mq_setattr(mqd_t mqdes, const struct mq_attr *mq_stat,
struct mq_attr *oldstat);
EXTERN int mq_getattr(mqd_t mqdes, struct mq_attr *mq_stat);

View File

@@ -173,9 +173,9 @@ void lib_releaselist(FAR struct streamlist *list)
/* Destroy the semaphore and release the filelist */
(void)sem_destroy(&list->sl_sem);
sched_free(list);
/* Initialize each FILE structure */
/* Release each stream in the list */
#if CONFIG_STDIO_BUFFER_SIZE > 0
for (i = 0; i < CONFIG_NFILE_STREAMS; i++)
{
@@ -190,6 +190,9 @@ void lib_releaselist(FAR struct streamlist *list)
}
}
#endif
/* Finally, release the list itself */
sched_free(list);
}
}
}

View File

@@ -87,7 +87,15 @@ int vfprintf(FILE *stream, const char *fmt, va_list ap)
*/
lib_stdstream(&stdstream, stream);
/* Hold the stream semaphore throughout the lib_vsprintf
* call so that this thread can get its entire message out
* before being pre-empted by the next thread.
*/
lib_take_semaphore(stream);
n = lib_vsprintf(&stdstream.public, fmt, ap);
lib_give_semaphore(stream);
}
return n;
}

View File

@@ -69,9 +69,11 @@ SIGNAL_SRCS = sig_initialize.c \
sig_unmaskpendingsignal.c sig_removependingsignal.c \
sig_releasependingsignal.c sig_lowest.c sig_mqnotempty.c \
sig_cleanup.c sig_received.c sig_deliver.c
MQUEUE_SRCS = mq_open.c mq_close.c mq_unlink.c mq_send.c mq_receive.c \
MQUEUE_SRCS = mq_open.c mq_close.c mq_unlink.c \
mq_send.c mq_timedsend.c mq_sndinternal.c \
mq_receive.c mq_timedreceive.c mq_rcvinternal.c \
mq_setattr.c mq_getattr.c mq_initialize.c mq_descreate.c \
mq_findnamed.c mq_msgfree.c mq_msgqfree.c
mq_findnamed.c mq_msgfree.c mq_msgqfree.c mq_waitirq.c
ifneq ($(CONFIG_DISABLE_SIGNALS),y)
MQUEUE_SRCS += mq_notify.c
endif

View File

@@ -1,4 +1,4 @@
/************************************************************
/****************************************************************************
* mq_internal.h
*
* Copyright (C) 2007 Gregory Nutt. All rights reserved.
@@ -31,14 +31,14 @@
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
************************************************************/
****************************************************************************/
#ifndef __MQ_INTERNAL_H
#define __MQ_INTERNAL_H
/************************************************************
/****************************************************************************
* Included Files
************************************************************/
****************************************************************************/
#include <sys/types.h>
#include <limits.h>
@@ -47,16 +47,15 @@
#include <signal.h>
#include <nuttx/compiler.h>
/************************************************************
/****************************************************************************
* Compilations Switches
************************************************************/
****************************************************************************/
/************************************************************
/****************************************************************************
* Definitions
************************************************************/
****************************************************************************/
#define MQ_MAX_BYTES CONFIG_MQ_MAXMSGSIZE
#define MQ_MAX_HWORDS ((MQ_MAX_BYTES + sizeof(uint16) - 1) / sizeof(uint16))
#define MQ_MAX_MSGS 16
#define MQ_PRIO_MAX _POSIX_MQ_PRIO_MAX
@@ -72,9 +71,9 @@
#define NUM_INTERRUPT_MSGS 8
/************************************************************
/****************************************************************************
* Global Type Declarations
************************************************************/
****************************************************************************/
enum mqalloc_e
{
@@ -85,23 +84,18 @@ enum mqalloc_e
typedef enum mqalloc_e mqalloc_t;
/* This structure describes one buffered POSIX message. */
/* NOTE: This structure is allocated from the same pool as MQ_type.
* Therefore, (1) it must have a fixed "mail" size, and (2) must
* exactly match MQ_type in size.
*/
struct mqmsg
{
/* The position of the following two field must exactly match
* MQ_type.
*/
FAR struct mqmsg *next; /* Forward link to next message */
ubyte type; /* (Used to manage allocations) */
ubyte priority; /* priority of message */
#if MQ_MAX_BYTES < 256
ubyte msglen; /* Message data length */
uint16 mail[MQ_MAX_HWORDS]; /* Message data */
#else
uint16 msglen; /* Message data length */
#endif
ubyte mail[MQ_MAX_BYTES]; /* Message data */
};
typedef struct mqmsg mqmsg_t;
@@ -142,9 +136,9 @@ struct mq_des
int oflags; /* Flags set when message queue was opened */
};
/************************************************************
/****************************************************************************
* Global Variables
************************************************************/
****************************************************************************/
/* This is a list of all opened message queues */
@@ -170,9 +164,9 @@ extern sq_queue_t g_msgfreeirq;
extern sq_queue_t g_desfree;
/************************************************************
/****************************************************************************
* Global Function Prototypes
************************************************************/
****************************************************************************/
#ifdef __cplusplus
#define EXTERN extern "C"
@@ -181,15 +175,35 @@ extern "C" {
#define EXTERN extern
#endif
/* Functions defined in mq_initialized.c *******************/
/* Functions defined in mq_initialize.c ************************************/
EXTERN void weak_function mq_initialize(void);
EXTERN void mq_desblockalloc(void);
EXTERN void mq_desblockalloc(void);
EXTERN mqd_t mq_descreate(FAR _TCB* mtcb, FAR msgq_t* msgq, int oflags);
EXTERN FAR msgq_t *mq_findnamed(const char *mq_name);
EXTERN void mq_msgfree(FAR mqmsg_t *mqmsg);
EXTERN void mq_msgqfree(FAR msgq_t *msgq);
EXTERN mqd_t mq_descreate(FAR _TCB* mtcb, FAR msgq_t* msgq, int oflags);
EXTERN FAR msgq_t *mq_findnamed(const char *mq_name);
EXTERN void mq_msgfree(FAR mqmsg_t *mqmsg);
EXTERN void mq_msgqfree(FAR msgq_t *msgq);
/* mq_waitirq.c ************************************************************/
EXTERN void mq_waitirq(FAR _TCB *wtcb);
/* mq_rcvinternal.c ********************************************************/
EXTERN int mq_verifyreceive(mqd_t mqdes, void *msg, size_t msglen);
EXTERN FAR mqmsg_t *mq_waitreceive(mqd_t mqdes);
EXTERN ssize_t mq_doreceive(mqd_t mqdes, mqmsg_t *mqmsg, void *ubuffer,
int *prio);
/* mq_sndinternal.c ********************************************************/
EXTERN int mq_verifysend(mqd_t mqdes, const void *msg, size_t msglen,
int prio);
EXTERN FAR mqmsg_t *mq_msgalloc(void);
EXTERN int mq_waitsend(mqd_t mqdes);
EXTERN int mq_dosend(mqd_t mqdes, FAR mqmsg_t *mqmsg, const void *msg,
size_t msglen, int prio);
#undef EXTERN
#ifdef __cplusplus

314
sched/mq_rcvinternal.c Normal file
View File

@@ -0,0 +1,314 @@
/************************************************************
* mq_rcvinternal.c
*
* Copyright (C) 2007 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
*
* 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 Gregory Nutt 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 COPYRIGHT HOLDERS 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
* COPYRIGHT OWNER 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.
*
************************************************************/
/************************************************************
* Included Files
************************************************************/
#include <sys/types.h>
#include <fcntl.h> /* O_NONBLOCK */
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <mqueue.h>
#include <sched.h>
#include <debug.h>
#include <nuttx/arch.h>
#include <nuttx/os_external.h>
#include "os_internal.h"
#include "mq_internal.h"
/************************************************************
* Definitions
************************************************************/
/************************************************************
* Private Type Declarations
************************************************************/
/************************************************************
* Global Variables
************************************************************/
/************************************************************
* Private Variables
************************************************************/
/************************************************************
* Private Functions
************************************************************/
/************************************************************
* Public Functions
************************************************************/
/************************************************************
* Name: mq_verifyreceive
*
* Description:
* This is internal, common logic shared by both mq_receive
* and mq_timedreceive. This function verifies the
* input parameters that are common to both functions.
*
* Parameters:
* mqdes - Message Queue Descriptor
* msg - Buffer to receive the message
* msglen - Size of the buffer in bytes
*
* Return Value:
* One success, 0 (OK) is returned. On failure, -1 (ERROR) is
* returned and the errno is set appropriately:
*
* EPERM Message queue opened not opened for reading.
* EMSGSIZE 'msglen' was less than the maxmsgsize attribute of the
* message queue.
* EINVAL Invalid 'msg' or 'mqdes'
*
* Assumptions:
*
************************************************************/
int mq_verifyreceive(mqd_t mqdes, void *msg, size_t msglen)
{
/* Verify the input parameters */
if (!msg || !mqdes)
{
*get_errno_ptr() = EINVAL;
return ERROR;
}
if ((mqdes->oflags & O_RDOK) == 0)
{
*get_errno_ptr() = EPERM;
return ERROR;
}
if (msglen < (size_t)mqdes->msgq->maxmsgsize)
{
*get_errno_ptr() = EMSGSIZE;
return ERROR;
}
return OK;
}
/************************************************************
* Function: mq_waitreceive
*
* Description:
* This is internal, common logic shared by both mq_receive
* and mq_timedreceive. This function waits for a message to
* be received on the specified message queue, removes the
* message from the queue, and returns it.
*
* Parameters:
* mqdes - Message queue descriptor
*
* Return Value:
* On success, a reference to the received message. If the
* wait was interrupted by a signal or a timeout, then the
* errno will be set appropriately and NULL will be returned.
*
* Assumptions:
* - The caller has provided all validity checking of the
* input parameters using mq_verifyreceive.
* - Interrupts should be disabled throughout this call. This
* is necessary because messages can be sent from interrupt
* level processing.
* - For mq_timedreceive, setting of the timer and this wait
* must be atomic.
*
************************************************************/
FAR mqmsg_t *mq_waitreceive(mqd_t mqdes)
{
FAR _TCB *rtcb;
FAR msgq_t *msgq;
FAR mqmsg_t *rcvmsg;
/* Get a pointer to the message queue */
msgq = mqdes->msgq;
/* Get the message from the head of the queue */
while ((rcvmsg = (FAR mqmsg_t*)sq_remfirst(&msgq->msglist)) == NULL)
{
/* Should we block until there the above condition has been
* satisfied?
*/
if (!(mqdes->oflags & O_NONBLOCK))
{
/* Block and try again */
rtcb = (FAR _TCB*)g_readytorun.head;
rtcb->msgwaitq = msgq;
msgq->nwaitnotempty++;
*get_errno_ptr() = OK;
up_block_task(rtcb, TSTATE_WAIT_MQNOTEMPTY);
/* When we resume at this point, either (1) the message queue
* is no longer empty, or (2) the wait has been interrupted by
* a signal. We can detect the latter case be examining the
* errno value (should be either EINTR or ETIMEDOUT).
*/
if (*get_errno_ptr() != OK)
{
break;
}
}
else
{
/* The queue was empty, and the O_NONBLOCK flag was set for the
* message queue description referred to by 'mqdes'.
*/
*get_errno_ptr() = EAGAIN;
break;
}
}
/* If we got message, then decrement the number of messages in
* the queue while we are still in the critical section
*/
if (rcvmsg)
{
msgq->nmsgs--;
}
return rcvmsg;
}
/************************************************************
* Function: mq_doreceive
*
* Description:
* This is internal, common logic shared by both mq_receive
* and mq_timedreceive. This function accepts the message
* obtained by mq_waitmsg, provides the message content to
* the user, notifies any threads that were waiting for
* the message queue to become non-full, and disposes of the
* message structure
*
* Parameters:
* mqdes - Message queue descriptor
* mqmsg - The message obtained by mq_waitmsg()
* ubuffer - The address of the user provided buffer to
* receive the message
* prio - The user-provided location to return the
* message priority.
*
* Return Value:
* Returns the length of the received message. This
* function does not fail.
*
* Assumptions:
* - The caller has provided all validity checking of the
* input parameters using mq_verifyreceive.
* - The user buffer, ubuffer, is known to be large enough
* to accept the largest message that an be sent on this
* message queue
* - Pre-emption should be disabled throughout this call.
*
************************************************************/
ssize_t mq_doreceive(mqd_t mqdes, mqmsg_t *mqmsg, void *ubuffer, int *prio)
{
FAR _TCB *btcb;
irqstate_t saved_state;
FAR msgq_t *msgq;
ssize_t rcvmsglen;
/* Get the length of the message (also the return value) */
rcvmsglen = mqmsg->msglen;
/* Copy the message into the caller's buffer */
memcpy(ubuffer, (const void*)mqmsg->mail, rcvmsglen);
/* Copy the message priority as well (if a buffer is provided) */
if (prio)
{
*prio = mqmsg->priority;
}
/* We are done with the message. Deallocate it now. */
mq_msgfree(mqmsg);
/* Check if any tasks are waiting for the MQ not full event. */
msgq = mqdes->msgq;
if (msgq->nwaitnotfull > 0)
{
/* Find the highest priority task that is waiting for
* this queue to be not-full in g_waitingformqnotfull list.
* This must be performed in a critical section because
* messages can be sent from interrupt handlers.
*/
saved_state = irqsave();
for (btcb = (FAR _TCB*)g_waitingformqnotfull.head;
btcb && btcb->msgwaitq != msgq;
btcb = btcb->flink);
/* If one was found, unblock it. NOTE: There is a race
* condition here: the queue might be full again by the
* time the task is unblocked
*/
if (!btcb)
{
PANIC(OSERR_MQNOTFULLCOUNT);
}
else
{
btcb->msgwaitq = NULL;
msgq->nwaitnotfull--;
up_unblock_task(btcb);
}
irqrestore(saved_state);
}
/* Return the length of the message transferred to the user buffer */
return rcvmsglen;
}

View File

@@ -37,20 +37,12 @@
* Included Files
************************************************************/
#include <sys/types.h> /* uint32, etc. */
#include <stdarg.h> /* va_list */
#include <unistd.h>
#include <fcntl.h> /* O_NONBLOCK */
#include <string.h>
#include <assert.h>
#include <nuttx/config.h>
#include <sys/types.h>
#include <errno.h>
#include <mqueue.h>
#include <sched.h>
#include <debug.h>
#include <nuttx/kmalloc.h>
#include <nuttx/arch.h>
#include <nuttx/os_external.h>
#include "os_internal.h"
#include "sig_internal.h"
#include "mq_internal.h"
/************************************************************
@@ -86,7 +78,7 @@
* "mqdes." If the size of the buffer in bytes (msglen) is
* less than the "mq_msgsize" attribute of the message
* queue, mq_receive will return an error. Otherwise, the
* select message is removed from the queue and copied to
* selected message is removed from the queue and copied to
* "msg."
*
* If the message queue is empty and O_NONBLOCK was not
@@ -102,134 +94,72 @@
* mqdes - Message Queue Descriptor
* msg - Buffer to receive the message
* msglen - Size of the buffer in bytes
* prio - If not NULL, the location to store message
* priority.
* prio - If not NULL, the location to store message priority.
*
* Return Value:
* Length of the selected message in bytes, otherwise -1
* (ERROR).
* One success, the length of the selected message in bytes.is
* returned. On failure, -1 (ERROR) is returned and the errno
* is set appropriately:
*
* EAGAIN The queue was empty, and the O_NONBLOCK flag was set
* for the message queue description referred to by 'mqdes'.
* EPERM Message queue opened not opened for reading.
* EMSGSIZE 'msglen' was less than the maxmsgsize attribute of the
* message queue.
* EINTR The call was interrupted by a signal handler.
* EINVAL Invalid 'msg' or 'mqdes'
*
* Assumptions:
*
************************************************************/
int mq_receive(mqd_t mqdes, void *msg, size_t msglen, int *prio)
ssize_t mq_receive(mqd_t mqdes, void *msg, size_t msglen, int *prio)
{
FAR _TCB *rtcb;
FAR _TCB *btcb;
FAR msgq_t *msgq;
FAR mqmsg_t *curr;
FAR mqmsg_t *mqmsg;
irqstate_t saved_state;
ubyte rcvmsglen;
int ret = ERROR;
ssize_t ret = ERROR;
/* Verify the input parameters */
DEBUGASSERT(!up_interrupt_context());
/* Verify the input parameters and, in case of an error, set
* errno appropriately.
*/
if (mq_verifyreceive(mqdes, msg, msglen) != OK)
{
return ERROR;
}
/* Get the next mesage from the message queue. We will disable
* pre-emption until we have completed the message received. This
* is not too bad because if the receipt takes a long time, it will
* be because we are blocked waiting for a message and pre-emption
* will be re-enabled while we are blocked
*/
sched_lock();
if (msg && mqdes && (mqdes->oflags & O_RDOK) != 0 &&
msglen >= (size_t)mqdes->msgq->maxmsgsize)
/* Furthermore, mq_waitreceive() expects to have interrupts disabled
* because messages can be sent from interrupt level.
*/
saved_state = irqsave();
/* Get the message from the message queue */
mqmsg = mq_waitreceive(mqdes);
irqrestore(saved_state);
/* Check if we got a message from the message queue. We might
* not have a message if:
*
* - The message queue is empty and O_NONBLOCK is set in the mqdes
* - The wait was interrupted by a signal
*/
if (mqmsg)
{
/* Get a pointer to the message queue */
msgq = mqdes->msgq;
/* Several operations must be performed below: We must determine if
* a message is pending and, if not, wait for the message. Since
* messages can be sent from the interrupt level, there is a race
* condition that can only be eliminated by disabling interrupts!
*/
saved_state = irqsave();
/* Get the message from the head of the queue */
while ((curr = (FAR mqmsg_t*)sq_remfirst(&msgq->msglist)) == NULL)
{
/* Should we block until there the above condition has been
* satisfied?
*/
if (!(mqdes->oflags & O_NONBLOCK))
{
/* Block and try again */
rtcb = (FAR _TCB*)g_readytorun.head;
rtcb->msgwaitq = msgq;
msgq->nwaitnotempty++;
up_block_task(rtcb, TSTATE_WAIT_MQNOTEMPTY);
}
else
{
break;
}
}
/* If we got message, then decrement the number of messages in
* the queue while we are still in the critical section
*/
if (curr)
{
msgq->nmsgs--;
}
irqrestore(saved_state);
/* Check (again) if we got a message from the message queue*/
if (curr)
{
/* Get the length of the message (also the return value) */
ret = rcvmsglen = curr->msglen;
/* Copy the message into the caller's buffer */
memcpy(msg, (const void*)curr->mail, rcvmsglen);
/* Copy the message priority as well (if a buffer is provided) */
if (prio)
{
*prio = curr->priority;
}
/* We are done with the message. Deallocate it now. */
mq_msgfree(curr);
/* Check if any tasks are waiting for the MQ not full event. */
if (msgq->nwaitnotfull > 0)
{
/* Find the highest priority task that is waiting for
* this queue to be not-full in g_waitingformqnotfull list.
* This must be performed in a critical section because
* messages can be sent from interrupt handlers.
*/
saved_state = irqsave();
for (btcb = (FAR _TCB*)g_waitingformqnotfull.head;
btcb && btcb->msgwaitq != msgq;
btcb = btcb->flink);
/* If one was found, unblock it. NOTE: There is a race
* condition here: the queue might be full again by the
* time the task is unblocked
*/
if (!btcb)
{
PANIC(OSERR_MQNOTFULLCOUNT);
}
else
{
btcb->msgwaitq = NULL;
msgq->nwaitnotfull--;
up_unblock_task(btcb);
}
irqrestore(saved_state);
}
}
ret = mq_doreceive(mqdes, mqmsg, msg, prio);
}
sched_unlock();

View File

@@ -1,4 +1,4 @@
/************************************************************
/****************************************************************************
* mq_send.c
*
* Copyright (C) 2007 Gregory Nutt. All rights reserved.
@@ -31,164 +31,65 @@
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
************************************************************/
****************************************************************************/
/************************************************************
/****************************************************************************
* Included Files
************************************************************/
****************************************************************************/
#include <nuttx/compiler.h>
#include <nuttx/kmalloc.h>
#include <sys/types.h> /* uint32, etc. */
#include <fcntl.h>
#include <nuttx/config.h>
#include <sys/types.h>
#include <mqueue.h>
#include <string.h>
#include <sched.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/arch.h>
#include "os_internal.h"
#ifndef CONFIG_DISABLE_SIGNALS
# include "sig_internal.h"
#endif
#include "mq_internal.h"
/************************************************************
/****************************************************************************
* Definitions
************************************************************/
****************************************************************************/
/************************************************************
/****************************************************************************
* Private Type Declarations
************************************************************/
****************************************************************************/
/************************************************************
/****************************************************************************
* Global Variables
************************************************************/
****************************************************************************/
/************************************************************
/****************************************************************************
* Private Variables
************************************************************/
****************************************************************************/
/************************************************************
* Function: mq_msgalloc
*
* Description:
* The mq_msgalloc function will get a free message for use
* by the operating system. The message will be allocated
* from the g_msgfree list.
*
* If the list is empty AND the message is NOT being
* allocated from the interrupt level, then the message
* will be allocated. If a message cannot be obtained,
* the operating system is dead and therefore cannot
* continue.
*
* If the list is empty AND the message IS being allocated
* from the interrupt level. This function will attempt to
* get a message from the g_msgfreeirq list. If this is
* unsuccessful, the calling interrupt handler will be
* notified.
*
* Inputs:
* None
*
* Return Value:
* A reference to the allocated msg structure
*
************************************************************/
FAR mqmsg_t *mq_msgalloc(void)
{
FAR mqmsg_t *mqmsg;
irqstate_t saved_state;
/* If we were called from an interrupt handler, then try to
* get the message from generally available list of messages.
* If this fails, then try the list of messages reserved for
* interrupt handlers
*/
if (up_interrupt_context())
{
/* Try the general free list */
mqmsg = (FAR mqmsg_t*)sq_remfirst(&g_msgfree);
if (!mqmsg)
{
/* Try the free list reserved for interrupt handlers */
mqmsg = (FAR mqmsg_t*)sq_remfirst(&g_msgfreeirq);
}
}
/* We were not called from an interrupt handler. */
else
{
/* Try to get the message from the generally available free list.
* Disable interrupts -- we might be called from an interrupt handler.
*/
saved_state = irqsave();
mqmsg = (FAR mqmsg_t*)sq_remfirst(&g_msgfree);
irqrestore(saved_state);
/* If we cannot a message from the free list, then we will have to allocate one. */
if (!mqmsg)
{
mqmsg = (FAR mqmsg_t *)kmalloc((sizeof (mqmsg_t)));
/* Check if we got an allocated message */
if (mqmsg)
{
mqmsg->type = MQ_ALLOC_DYN;
}
/* No? We are dead */
else
{
dbg("Out of messages\n");
PANIC((uint32)OSERR_OUTOFMESSAGES);
}
}
}
return(mqmsg);
}
/************************************************************
/****************************************************************************
* Private Functions
************************************************************/
****************************************************************************/
/************************************************************
/****************************************************************************
* Public Functions
************************************************************/
****************************************************************************/
/************************************************************
/****************************************************************************
* Function: mq_send
*
* Description:
* This function adds the specificied message (msg) to the
* message queue (mqdes). The "msglen" parameter specifies
* the length of the message in bytes pointed to by "msg."
* This length must not exceed the maximum message length
* from the mq_getattr().
* This function adds the specificied message (msg) to the message queue
* (mqdes). The "msglen" parameter specifies the length of the message
* in bytes pointed to by "msg." This length must not exceed the maximum
* message length from the mq_getattr().
*
* If the message queue is not full, mq_send() will in the
* message in the message queue at the position indicated
* by the "prio" argrument. Messages with higher priority
* will be inserted before lower priority messages. The
* value of "prio" must not exceed MQ_PRIO_MAX.
* If the message queue is not full, mq_send() place the message in the
* message queue at the position indicated by the "prio" argrument.
* Messages with higher priority will be inserted before lower priority
* messages. The value of "prio" must not exceed MQ_PRIO_MAX.
*
* If the specified message queue is full and O_NONBLOCK
* is not set in the message queue, then mq_send() will
* block until space becomes available to the queue the
* message.
* If the specified message queue is full and O_NONBLOCK is not set in the
* message queue, then mq_send() will block until space becomes available
* to the queue the message.
*
* If the message queue is full and O_NONBLOCK is set,
* the message is not queued and ERROR is returned.
* If the message queue is full and O_NONBLOCK is set, the message is not
* queued and ERROR is returned.
*
* Parameters:
* mqdes - Message queue descriptor
@@ -197,214 +98,84 @@ FAR mqmsg_t *mq_msgalloc(void)
* prio - The priority of the message
*
* Return Value:
* None
* On success, mq_send() returns 0 (OK); on error, -1 (ERROR)
* is returned, with errno set to indicate the error:
*
* EAGAIN The queue was empty, and the O_NONBLOCK flag was set for the
* message queue description referred to by mqdes.
* EINVAL Either msg or mqdes is NULL or the value of prio is invalid.
* EPERM Message queue opened not opened for writing.
* EMSGSIZE 'msglen' was greater than the maxmsgsize attribute of the
* message queue.
* EINTR The call was interrupted by a signal handler.
*
* Assumptions/restrictions:
*
************************************************************/
****************************************************************************/
int mq_send(mqd_t mqdes, const void *msg, size_t msglen, int prio)
{
FAR _TCB *rtcb;
FAR _TCB *btcb;
FAR msgq_t *msgq;
FAR mqmsg_t *curr;
FAR mqmsg_t *next;
FAR mqmsg_t *prev;
FAR mqmsg_t *mqmsg = NULL;
irqstate_t saved_state;
int ret = ERROR;
/* Verify the input parameters */
/* Verify the input parameters -- setting errno appropriately
* on any failures to verify.
*/
if (mq_verifysend(mqdes, msg, msglen, prio) != OK)
{
return ERROR;
}
/* Get a pointer to the message queue */
sched_lock();
if (msg && mqdes && (mqdes->oflags & O_WROK) != 0 &&
msglen > 0 && msglen <= (size_t)mqdes->msgq->maxmsgsize &&
prio >= 0 && prio <= MQ_PRIO_MAX)
msgq = mqdes->msgq;
/* Allocate a message structure:
* - Immediately if we are called from an interrupt handler.
* - Immediately if the message queue is not full, or
* - After successfully waiting for the message queue to become
* non-FULL. This would fail with EAGAIN, EINTR, or ETIMEOUT.
*/
saved_state = irqsave();
if (up_interrupt_context() || /* In an interrupt handler */
msgq->nmsgs < msgq->maxmsgs || /* OR Message queue not full */
mq_waitsend(mqdes) == OK) /* OR Successfully waited for mq not full */
{
/* Get a pointer to the message queue */
/* Allocate the message */
msgq = mqdes->msgq;
/* If we are sending a message from an interrupt handler, then
* try to get message structure unconditionally.
*/
saved_state = irqsave();
if (up_interrupt_context())
{
curr = mq_msgalloc();
}
/* Otherwise, arbitrarily limit the number of messages in the
* queue to the value determined when the message queue was opened.
* This makes us more POSIX-like as well as prohibits one slow
* responding task from consuming all available memory.
*/
else if (msgq->nmsgs >= msgq->maxmsgs)
{
/* Should we block until there is sufficient space in the
* message queue?
*/
if ((mqdes->oflags & O_NONBLOCK) != 0)
{
/* No... We will return an error to the caller. */
curr = NULL;
}
/* Yes... We will not return control until the message queue is
* available.
*/
else
{
/* Loop until there are fewer than max allowable messages in the
* receiving message queue
*/
while (msgq->nmsgs >= msgq->maxmsgs)
{
/* Block until the message queue is no longer full.
* When we are unblocked, we will try again
*/
rtcb = (FAR _TCB*)g_readytorun.head;
rtcb->msgwaitq = msgq;
(msgq->nwaitnotfull)++;
up_block_task(rtcb, TSTATE_WAIT_MQNOTFULL);
}
/* It should be okay to get add a message to the receiving
* message queue now.
*/
curr = mq_msgalloc();
}
}
/* We are not in an interrupt handler and the receiving message queue
* is not full
*/
else
{
/* Just allocate a message */
curr = mq_msgalloc();
}
irqrestore(saved_state);
mqmsg = mq_msgalloc();
}
else
{
/* We cannot send the message (and didn't even try to allocate it)
* because:
* - We are not in an interrupt handler AND
* - The message queue is full AND
* - When we tried waiting, the wait was unsuccessful.
*/
/* Check if we were able to get a message structure */
irqrestore(saved_state);
}
if (curr)
{
/* Construct the current message header info */
/* Check if we were able to get a message structure -- this can fail
* either because we cannot send the message (and didn't bother trying
* to allocate it) or because the allocation failed.
*/
curr->priority = (ubyte)prio;
curr->msglen = (ubyte)msglen;
if (mqmsg)
{
/* Yes, peforrm the message send. */
/* Copy the message data into the message */
memcpy((void*)curr->mail, (const void*)msg, msglen);
/* Insert the new message in the message queue */
saved_state = irqsave();
/* Search the message list to find the location to insert the new
* message. Each is list is maintained in ascending priority order.
*/
for (prev = NULL, next = (FAR mqmsg_t*)msgq->msglist.head;
next && prio <= next->priority;
prev = next, next = next->next);
/* Add the message at the right place */
if (prev)
{
sq_addafter((FAR sq_entry_t*)prev, (FAR sq_entry_t*)curr,
&msgq->msglist);
}
else
{
sq_addfirst((FAR sq_entry_t*)curr, &msgq->msglist);
}
/* Increment the count of message in the queue */
msgq->nmsgs++;
irqrestore(saved_state);
/* Check if we need to notify any tasks that are attached to the
* message queue
*/
#ifndef CONFIG_DISABLE_SIGNALS
if (msgq->ntmqdes)
{
/* Remove the message notification data from the message queue. */
#ifdef CONFIG_CAN_PASS_STRUCTS
union sigval value = msgq->ntvalue;
#else
void *sival_ptr = msgq->ntvalue.sival_ptr;
#endif
int signo = msgq->ntsigno;
int pid = msgq->ntpid;
/* Detach the notification */
msgq->ntpid = INVALID_PROCESS_ID;
msgq->ntsigno = 0;
msgq->ntvalue.sival_int = 0;
msgq->ntmqdes = NULL;
/* Queue the signal -- What if this returns an error? */
#ifdef CONFIG_CAN_PASS_STRUCTS
sig_mqnotempty(pid, signo, value);
#else
sig_mqnotempty(pid, signo, sival_ptr);
#endif
}
#endif
/* Check if any tasks are waiting for the MQ not empty event. */
saved_state = irqsave();
if (msgq->nwaitnotempty > 0)
{
/* Find the highest priority task that is waiting for
* this queue to be non-empty in g_waitingformqnotempty
* list. sched_lock() should give us sufficent protection since
* interrupts should never cause a change in this list
*/
for (btcb = (FAR _TCB*)g_waitingformqnotempty.head;
btcb && btcb->msgwaitq != msgq;
btcb = btcb->flink);
/* If one was found, unblock it */
if (!btcb)
{
PANIC(OSERR_MQNONEMPTYCOUNT);
}
else
{
btcb->msgwaitq = NULL;
msgq->nwaitnotempty--;
up_unblock_task(btcb);
}
}
irqrestore(saved_state);
ret = OK;
}
ret = mq_dosend(mqdes, mqmsg, msg, msglen, prio);
}
sched_unlock();
return(ret);
return ret;
}

448
sched/mq_sndinternal.c Normal file
View File

@@ -0,0 +1,448 @@
/****************************************************************************
* mq_send.c
*
* Copyright (C) 2007 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
*
* 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 Gregory Nutt 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 COPYRIGHT HOLDERS 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
* COPYRIGHT OWNER 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/kmalloc.h>
#include <sys/types.h>
#include <fcntl.h>
#include <mqueue.h>
#include <string.h>
#include <errno.h>
#include <sched.h>
#include <debug.h>
#include <nuttx/arch.h>
#include "os_internal.h"
#ifndef CONFIG_DISABLE_SIGNALS
# include "sig_internal.h"
#endif
#include "mq_internal.h"
/****************************************************************************
* Definitions
****************************************************************************/
/****************************************************************************
* Private Type Declarations
****************************************************************************/
/****************************************************************************
* Global Variables
****************************************************************************/
/****************************************************************************
* Private Variables
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: mq_verifysend
*
* Description:
* This is internal, common logic shared by both mq_send and mq_timesend.
* This function verifies the input parameters that are common to both
* functions.
*
* Parameters:
* mqdes - Message queue descriptor
* msg - Message to send
* msglen - The length of the message in bytes
* prio - The priority of the message
*
* Return Value:
* One success, 0 (OK) is returned. On failure, -1 (ERROR) is returned and
* the errno is set appropriately:
*
* EINVAL Either msg or mqdes is NULL or the value of prio is invalid.
* EPERM Message queue opened not opened for writing.
* EMSGSIZE 'msglen' was greater than the maxmsgsize attribute of the
* message queue.
*
* Assumptions:
*
****************************************************************************/
int mq_verifysend(mqd_t mqdes, const void *msg, size_t msglen, int prio)
{
/* Verify the input parameters */
if (!msg || !mqdes || prio < 0 || prio > MQ_PRIO_MAX)
{
*get_errno_ptr() = EINVAL;
return ERROR;
}
if ((mqdes->oflags & O_WROK) == 0)
{
*get_errno_ptr() = EPERM;
return ERROR;
}
if (msglen < 0 || msglen > (size_t)mqdes->msgq->maxmsgsize)
{
*get_errno_ptr() = EMSGSIZE;
return ERROR;
}
return OK;
}
/****************************************************************************
* Function: mq_msgalloc
*
* Description:
* The mq_msgalloc function will get a free message for use by the
* operating system. The message will be allocated from the g_msgfree list.
*
* If the list is empty AND the message is NOT being allocated from the
* interrupt level, then the message will be allocated. If a message
* cannot be obtained, the operating system is dead and therefore cannot
* continue.
*
* If the list is empty AND the message IS being allocated from the
* interrupt level. This function will attempt to get a message from
* the g_msgfreeirq list. If this is unsuccessful, the calling interrupt
* handler will be notified.
*
* Inputs:
* None
*
* Return Value:
* A reference to the allocated msg structure. On a failure to allocate,
* this function PANICs.
*
****************************************************************************/
FAR mqmsg_t *mq_msgalloc(void)
{
FAR mqmsg_t *mqmsg;
irqstate_t saved_state;
/* If we were called from an interrupt handler, then try to get the message
* from generally available list of messages. If this fails, then try the
* list of messages reserved for interrupt handlers
*/
if (up_interrupt_context())
{
/* Try the general free list */
mqmsg = (FAR mqmsg_t*)sq_remfirst(&g_msgfree);
if (!mqmsg)
{
/* Try the free list reserved for interrupt handlers */
mqmsg = (FAR mqmsg_t*)sq_remfirst(&g_msgfreeirq);
}
}
/* We were not called from an interrupt handler. */
else
{
/* Try to get the message from the generally available free list.
* Disable interrupts -- we might be called from an interrupt handler.
*/
saved_state = irqsave();
mqmsg = (FAR mqmsg_t*)sq_remfirst(&g_msgfree);
irqrestore(saved_state);
/* If we cannot a message from the free list, then we will have to allocate one. */
if (!mqmsg)
{
mqmsg = (FAR mqmsg_t *)kmalloc((sizeof (mqmsg_t)));
/* Check if we got an allocated message */
if (mqmsg)
{
mqmsg->type = MQ_ALLOC_DYN;
}
/* No? We are dead */
else
{
dbg("Out of messages\n");
PANIC((uint32)OSERR_OUTOFMESSAGES);
}
}
}
return mqmsg;
}
/****************************************************************************
* Function: mq_waitsend
*
* Description:
* This is internal, common logic shared by both mq_send and mq_timesend.
* This function waits until the message queue is not full.
*
* Parameters:
* mqdes - Message queue descriptor
*
* Return Value:
* On success, mq_send() returns 0 (OK); on error, -1 (ERROR) is
* returned, with errno set to indicate the error:
*
* EAGAIN The queue was empty, and the O_NONBLOCK flag was set for the
* message queue description referred to by mqdes.
* EINTR The call was interrupted by a signal handler.
* ETIMEOUT A timeout expired before the message queue became non-full
* (mq_timedsend only).
*
* Assumptions/restrictions:
* - The caller has verified the input parameters using mq_verifysend().
* - Interrupts are disabled.
*
****************************************************************************/
int mq_waitsend(mqd_t mqdes)
{
FAR _TCB *rtcb;
FAR msgq_t *msgq;
/* Get a pointer to the message queue */
msgq = mqdes->msgq;
/* Verify that the queue is indeed full as the caller thinks */
if (msgq->nmsgs >= msgq->maxmsgs)
{
/* Should we block until there is sufficient space in the
* message queue?
*/
if ((mqdes->oflags & O_NONBLOCK) != 0)
{
/* No... We will return an error to the caller. */
*get_errno_ptr() = EAGAIN;
return ERROR;
}
/* Yes... We will not return control until the message queue is
* available or we receive a signal or at timout occurs.
*/
else
{
/* Loop until there are fewer than max allowable messages in the
* receiving message queue
*/
while (msgq->nmsgs >= msgq->maxmsgs)
{
/* Block until the message queue is no longer full.
* When we are unblocked, we will try again
*/
rtcb = (FAR _TCB*)g_readytorun.head;
rtcb->msgwaitq = msgq;
(msgq->nwaitnotempty)++;
*get_errno_ptr() = OK;
up_block_task(rtcb, TSTATE_WAIT_MQNOTFULL);
/* When we resume at this point, either (1) the message queue
* is no longer empty, or (2) the wait has been interrupted by
* a signal. We can detect the latter case be examining the
* errno value (should be EINTR or ETIMEOUT).
*/
if (*get_errno_ptr() != OK)
{
return ERROR;
}
}
}
}
return OK;
}
/****************************************************************************
* Function: mq_dosend
*
* Description:
* This is internal, common logic shared by both mq_send and mq_timesend.
* This function adds the specificied message (msg) to the message queue
* (mqdes). Then it notifies any tasks that were waiting for message
* queue notifications setup by mq_notify. And, finally, it awakens any
* tasks that were waiting for the message not empty event.
*
* Parameters:
* mqdes - Message queue descriptor
* msg - Message to send
* msglen - The length of the message in bytes
* prio - The priority of the message
*
* Return Value:
* This function always returns OK.
*
* Assumptions/restrictions:
*
****************************************************************************/
int mq_dosend(mqd_t mqdes, FAR mqmsg_t *mqmsg, const void *msg, size_t msglen, int prio)
{
FAR _TCB *btcb;
FAR msgq_t *msgq;
FAR mqmsg_t *next;
FAR mqmsg_t *prev;
irqstate_t saved_state;
/* Get a pointer to the message queue */
sched_lock();
msgq = mqdes->msgq;
/* Construct the message header info */
mqmsg->priority = prio;
mqmsg->msglen = msglen;
/* Copy the message data into the message */
memcpy((void*)mqmsg->mail, (const void*)msg, msglen);
/* Insert the new message in the message queue */
saved_state = irqsave();
/* Search the message list to find the location to insert the new
* message. Each is list is maintained in ascending priority order.
*/
for (prev = NULL, next = (FAR mqmsg_t*)msgq->msglist.head;
next && prio <= next->priority;
prev = next, next = next->next);
/* Add the message at the right place */
if (prev)
{
sq_addafter((FAR sq_entry_t*)prev, (FAR sq_entry_t*)mqmsg,
&msgq->msglist);
}
else
{
sq_addfirst((FAR sq_entry_t*)mqmsg, &msgq->msglist);
}
/* Increment the count of messages in the queue */
msgq->nmsgs++;
irqrestore(saved_state);
/* Check if we need to notify any tasks that are attached to the
* message queue
*/
#ifndef CONFIG_DISABLE_SIGNALS
if (msgq->ntmqdes)
{
/* Remove the message notification data from the message queue. */
#ifdef CONFIG_CAN_PASS_STRUCTS
union sigval value = msgq->ntvalue;
#else
void *sival_ptr = msgq->ntvalue.sival_ptr;
#endif
int signo = msgq->ntsigno;
int pid = msgq->ntpid;
/* Detach the notification */
msgq->ntpid = INVALID_PROCESS_ID;
msgq->ntsigno = 0;
msgq->ntvalue.sival_int = 0;
msgq->ntmqdes = NULL;
/* Queue the signal -- What if this returns an error? */
#ifdef CONFIG_CAN_PASS_STRUCTS
sig_mqnotempty(pid, signo, value);
#else
sig_mqnotempty(pid, signo, sival_ptr);
#endif
}
#endif
/* Check if any tasks are waiting for the MQ not empty event. */
saved_state = irqsave();
if (msgq->nwaitnotempty > 0)
{
/* Find the highest priority task that is waiting for
* this queue to be non-empty in g_waitingformqnotempty
* list. sched_lock() should give us sufficent protection since
* interrupts should never cause a change in this list
*/
for (btcb = (FAR _TCB*)g_waitingformqnotempty.head;
btcb && btcb->msgwaitq != msgq;
btcb = btcb->flink);
/* If one was found, unblock it */
if (!btcb)
{
PANIC(OSERR_MQNONEMPTYCOUNT);
}
else
{
btcb->msgwaitq = NULL;
msgq->nwaitnotempty--;
up_unblock_task(btcb);
}
}
irqrestore(saved_state);
sched_unlock();
return OK;
}

308
sched/mq_timedreceive.c Normal file
View File

@@ -0,0 +1,308 @@
/****************************************************************************
* mq_timedreceive.c
*
* Copyright (C) 2007 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
*
* 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 Gregory Nutt 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 COPYRIGHT HOLDERS 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
* COPYRIGHT OWNER 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <mqueue.h>
#include <wdog.h>
#include <debug.h>
#include <nuttx/arch.h>
#include "os_internal.h"
#include "clock_internal.h"
#include "mq_internal.h"
/****************************************************************************
* Definitions
****************************************************************************/
/****************************************************************************
* Private Type Declarations
****************************************************************************/
/****************************************************************************
* Global Variables
****************************************************************************/
/****************************************************************************
* Private Variables
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Function: mq_rcvtimeout
*
* Description:
* This function is called if the timeout elapses before the message queue
* becomes non-empty.
*
* Parameters:
* argc - the number of arguments (should be 1)
* pid - the task ID of the task to wakeup
*
* Return Value:
* None
*
* Assumptions:
*
****************************************************************************/
static void mq_rcvtimeout(int argc, uint32 pid, ...)
{
FAR _TCB *wtcb;
irqstate_t saved_state;
/* Disable interrupts. This is necessary because an
* interrupt handler may attempt to send a message while we are
* doing this.
*/
saved_state = irqsave();
/* Get the TCB associated with this pid. It is possible that
* task may no longer be active when this watchdog goes off.
*/
wtcb = sched_gettcb((pid_t)pid);
/* It is also possible that an interrupt/context switch beat us to the
* punch and already changed the task's state.
*/
if (wtcb && wtcb->task_state == TSTATE_WAIT_MQNOTEMPTY)
{
/* Mark the errno value for the thread. */
wtcb->errno = ETIMEDOUT;
/* Restart the the task. */
up_unblock_task(wtcb);
}
/* Interrupts may now be enabled. */
irqrestore(saved_state);
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Function: mq_timedreceive
*
* Description:
* This function receives the oldest of the highest
* priority messages from the message queue specified by
* "mqdes." If the size of the buffer in bytes (msglen) is
* less than the "mq_msgsize" attribute of the message
* queue, mq_timedreceive will return an error. Otherwise, the
* selected message is removed from the queue and copied to
* "msg."
*
* If the message queue is empty and O_NONBLOCK was not
* set, mq_timedreceive() will block until a message is added
* to the message queue (or until a timeout occurs). If more
* than one task is waiting to receive a message, only the
* task with the highest priority that has waited the longest
* will be unblocked.
*
* mq_timedreceive() behaves just like mq_receive(), except
* that if the queue is empty and the O_NONBLOCK flag is not
* enabled for the message queue description, then abstime
* points to a structure which specifies a ceiling on the time
* for which the call will block. This ceiling is an absolute
* timeout in seconds and nanoseconds since the Epoch (midnight
* on the morning of 1 January 1970).
*
* If no message is available, and the timeout has already
* expired by the time of the call, mq_timedreceive() returns
* immediately.
*
* Parameters:
* mqdes - Message Queue Descriptor
* msg - Buffer to receive the message
* msglen - Size of the buffer in bytes
* prio - If not NULL, the location to store message priority.
* abstime - the absolute time to wait until a timeout is declared.
*
* Return Value:
* One success, the length of the selected message in bytes.is
* returned. On failure, -1 (ERROR) is returned and the errno
* is set appropriately:
*
* EAGAIN The queue was empty, and the O_NONBLOCK flag was set
* for the message queue description referred to by 'mqdes'.
* EPERM Message queue opened not opened for reading.
* EMSGSIZE 'msglen' was less than the maxmsgsize attribute of the
* message queue.
* EINTR The call was interrupted by a signal handler.
* EINVAL Invalid 'msg' or 'mqdes' or 'abstime'
* ETIMEDOUT The call timed out before a message could be transferred.
*
* Assumptions:
*
****************************************************************************/
ssize_t mq_timedreceive(mqd_t mqdes, void *msg, size_t msglen,
int *prio, const struct timespec *abstime)
{
WDOG_ID wdog;
FAR mqmsg_t *mqmsg;
irqstate_t saved_state;
int ret = ERROR;
DEBUGASSERT(!up_interrupt_context());
/* Verify the input parameters and, in case of an error, set
* errno appropriately.
*/
if (mq_verifyreceive(mqdes, msg, msglen) != OK)
{
return ERROR;
}
if (!abstime || abstime->tv_sec < 0 || abstime->tv_nsec > 1000000000)
{
*get_errno_ptr() = EINVAL;
return ERROR;
}
/* Create a watchdog. We will not actually need this watchdog
* unless the queue is not empty, but we will reserve it up front
* before we enter the following critical section.
*/
wdog = wd_create();
if (!wdog)
{
*get_errno_ptr() = EINVAL;
return ERROR;
}
/* Get the next mesage from the message queue. We will disable
* pre-emption until we have completed the message received. This
* is not too bad because if the receipt takes a long time, it will
* be because we are blocked waiting for a message and pre-emption
* will be re-enabled while we are blocked
*/
sched_lock();
/* Furthermore, mq_waitreceive() expects to have interrupts disabled
* because messages can be sent from interrupt level.
*/
saved_state = irqsave();
/* Check if the message queue is empty. If it is NOT empty, then we
* will not need to start timer.
*/
if (mqdes->msgq->msglist.head == NULL)
{
sint32 ticks;
/* Convert the timespec to clock ticks. We must have interrupts
* disabled here so that this time stays valid until the wait begins.
*/
int result = clock_abstime2ticks(CLOCK_REALTIME, abstime, &ticks);
/* If the time has already expired and the message queue is empty,
* return immediately.
*/
if (result == OK && ticks <= 0)
{
result = ETIMEDOUT;
}
/* Handle any time-related errors */
if (result != OK)
{
*get_errno_ptr() = result;
irqrestore(saved_state);
sched_unlock();
wd_delete(wdog);
return ERROR;
}
/* Start the watchdog */
wd_start(wdog, ticks, (wdentry_t)mq_rcvtimeout, 1, getpid());
}
/* Get the message from the message queue */
mqmsg = mq_waitreceive(mqdes);
/* Stop the watchdog timer (this is not harmful in the case where
* it was never started)
*/
wd_cancel(wdog);
/* We can now restore interrupts */
irqrestore(saved_state);
/* Check if we got a message from the message queue. We might
* not have a message if:
*
* - The message queue is empty and O_NONBLOCK is set in the mqdes
* - The wait was interrupted by a signal
* - The watchdog timeout expired
*/
if (mqmsg)
{
ret = mq_doreceive(mqdes, mqmsg, msg, prio);
}
sched_unlock();
wd_delete(wdog);
return ret;
}

320
sched/mq_timedsend.c Normal file
View File

@@ -0,0 +1,320 @@
/****************************************************************************
* mq_timedsend.c
*
* Copyright (C) 2007 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
*
* 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 Gregory Nutt 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 COPYRIGHT HOLDERS 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
* COPYRIGHT OWNER 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <unistd.h>
#include <mqueue.h>
#include <wdog.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/arch.h>
#include "clock_internal.h"
#include "os_internal.h"
#include "mq_internal.h"
/****************************************************************************
* Definitions
****************************************************************************/
/****************************************************************************
* Private Type Declarations
****************************************************************************/
/****************************************************************************
* Global Variables
****************************************************************************/
/****************************************************************************
* Private Variables
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Function: mq_sndtimeout
*
* Description:
* This function is called if the timeout elapses before the message queue
* becomes non-full.
*
* Parameters:
* argc - the number of arguments (should be 1)
* pid - the task ID of the task to wakeup
*
* Return Value:
* None
*
* Assumptions:
*
****************************************************************************/
static void mq_sndtimeout(int argc, uint32 pid, ...)
{
FAR _TCB *wtcb;
irqstate_t saved_state;
/* Disable interrupts. This is necessary because an
* interrupt handler may attempt to send a message while we are
* doing this.
*/
saved_state = irqsave();
/* Get the TCB associated with this pid. It is possible that
* task may no longer be active when this watchdog goes off.
*/
wtcb = sched_gettcb((pid_t)pid);
/* It is also possible that an interrupt/context switch beat us to the
* punch and already changed the task's state.
*/
if (wtcb && wtcb->task_state == TSTATE_WAIT_MQNOTFULL)
{
/* Mark the errno value for the thread. */
wtcb->errno = ETIMEDOUT;
/* Restart the the task. */
up_unblock_task(wtcb);
}
/* Interrupts may now be enabled. */
irqrestore(saved_state);
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Function: mq_send
*
* Description:
* This function adds the specificied message (msg) to the message queue
* (mqdes). The "msglen" parameter specifies the length of the message
* in bytes pointed to by "msg." This length must not exceed the maximum
* message length from the mq_getattr().
*
* If the message queue is not full, mq_timedsend() place the message in the
* message queue at the position indicated by the "prio" argrument.
* Messages with higher priority will be inserted before lower priority
* messages. The value of "prio" must not exceed MQ_PRIO_MAX.
*
* If the specified message queue is full and O_NONBLOCK is not set in the
* message queue, then mq_timedsend() will block until space becomes available
* to the queue the message or a timeout occurs.
*
* mq_timedsend() behaves just like mq_send(), except that if the queue
* is full and the O_NONBLOCK flag is not enabled for the message queue
* description, then abstime points to a structure which specifies a
* ceiling on the time for which the call will block. This ceiling is an
* absolute timeout in seconds and nanoseconds since the Epoch (midnight
* on the morning of 1 January 1970).
*
* If the message queue is full, and the timeout has already expired by
* the time of the call, mq_timedsend() returns immediately.
*
* Parameters:
* mqdes - Message queue descriptor
* msg - Message to send
* msglen - The length of the message in bytes
* prio - The priority of the message
* abstime - the absolute time to wait until a timeout is decleared
*
* Return Value:
* On success, mq_send() returns 0 (OK); on error, -1 (ERROR)
* is returned, with errno set to indicate the error:
*
* EAGAIN The queue was empty, and the O_NONBLOCK flag was set for the
* message queue description referred to by mqdes.
* EINVAL Either msg or mqdes is NULL or the value of prio is invalid.
* EPERM Message queue opened not opened for writing.
* EMSGSIZE 'msglen' was greater than the maxmsgsize attribute of the
* message queue.
* EINTR The call was interrupted by a signal handler.
*
* Assumptions/restrictions:
*
****************************************************************************/
int mq_timedsend(mqd_t mqdes, const char *msg, size_t msglen, int prio,
const struct timespec *abstime)
{
WDOG_ID wdog;
FAR msgq_t *msgq;
FAR mqmsg_t *mqmsg = NULL;
irqstate_t saved_state;
int ret = ERROR;
DEBUGASSERT(!up_interrupt_context());
/* Verify the input parameters -- setting errno appropriately
* on any failures to verify.
*/
if (mq_verifysend(mqdes, msg, msglen, prio) != OK)
{
return ERROR;
}
if (!abstime || abstime->tv_sec < 0 || abstime->tv_nsec > 1000000000)
{
*get_errno_ptr() = EINVAL;
return ERROR;
}
/* Get a pointer to the message queue */
msgq = mqdes->msgq;
/* Create a watchdog. We will not actually need this watchdog
* unless the queue is full, but we will reserve it up front
* before we enter the following critical section.
*/
wdog = wd_create();
if (!wdog)
{
*get_errno_ptr() = EINVAL;
return ERROR;
}
/* Allocate a message structure:
* - If we are called from an interrupt handler, or
* - If the message queue is not full, or
*/
sched_lock();
saved_state = irqsave();
if (up_interrupt_context() || /* In an interrupt handler */
msgq->nmsgs < msgq->maxmsgs) /* OR Message queue not full */
{
/* Allocate the message */
irqrestore(saved_state);
mqmsg = mq_msgalloc();
}
else
{
sint32 ticks;
/* We are not in an interupt handler and the message queue is full.
* set up a timed wait for the message queue to become non-full.
*
* Convert the timespec to clock ticks. We must have interrupts
* disabled here so that this time stays valid until the wait begins.
*/
int result = clock_abstime2ticks(CLOCK_REALTIME, abstime, &ticks);
/* If the time has already expired and the message queue is empty,
* return immediately.
*/
if (result == OK && ticks <= 0)
{
result = ETIMEDOUT;
}
/* Handle any time-related errors */
if (result != OK)
{
*get_errno_ptr() = result;
ret = ERROR;
}
/* Start the watchdog and begin the wait for MQ not full */
if (result == OK)
{
/* Start the watchdog */
wd_start(wdog, ticks, (wdentry_t)mq_sndtimeout, 1, getpid());
/* And wait for the message queue to be non-empty */
ret = mq_waitsend(mqdes);
/* This may return with an error and errno set to either EINTR
* or ETIMEOUT. Cancel the watchdog timer in any event.
*/
wd_cancel(wdog);
}
/* That is the end of the atomic operations */
irqrestore(saved_state);
/* If any of the above failed, set the errno. Otherwise, there should
* be space for another message in the message queue. NOW we can allocate
* the message structure.
*/
if (ret == OK)
{
mqmsg = mq_msgalloc();
}
}
/* Check if we were able to get a message structure -- this can fail
* either because we cannot send the message (and didn't bother trying
* to allocate it) or because the allocation failed.
*/
if (mqmsg)
{
/* Yes, peform the message send. */
ret = mq_dosend(mqdes, mqmsg, msg, msglen, prio);
}
sched_unlock();
wd_delete(wdog);
return ret;
}

125
sched/mq_waitirq.c Normal file
View File

@@ -0,0 +1,125 @@
/************************************************************
* mq_waitirq.c
*
* Copyright (C) 2007 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
*
* 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 Gregory Nutt 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 COPYRIGHT HOLDERS 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
* COPYRIGHT OWNER 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.
*
************************************************************/
/************************************************************
* Included Files
************************************************************/
#include <sys/types.h>
#include <sched.h>
#include <errno.h>
#include <nuttx/arch.h>
#include "sem_internal.h"
/************************************************************
* Compilation Switches
************************************************************/
/************************************************************
* Definitions
************************************************************/
/************************************************************
* Private Type Declarations
************************************************************/
/************************************************************
* Global Variables
************************************************************/
/************************************************************
* Private Variables
************************************************************/
/************************************************************
* Private Functions
************************************************************/
/************************************************************
* Public Functions
************************************************************/
/************************************************************
* Function: sem_waitirq
*
* Description:
* This function is called when a signal is received by a
* task that is waiting on a message queue -- either for a
* queue to becoming not full (on mq_send) or not empty
* (on mq_receive).
*
* Parameters:
* wtcb - A pointer to the TCB of the task that is waiting
* on a message queue, but has received a signal instead.
*
* Return Value:
* None
*
* Assumptions:
*
************************************************************/
void mq_waitirq(FAR _TCB *wtcb)
{
irqstate_t saved_state;
/* Disable interrupts. This is necessary because an
* interrupt handler may attempt to send a message while we are
* doing this.
*/
saved_state = irqsave();
/* It is possible that an interrupt/context switch beat us to the
* punch and already changed the task's state.
*/
if (wtcb->task_state == TSTATE_WAIT_MQNOTEMPTY ||
wtcb->task_state == TSTATE_WAIT_MQNOTFULL)
{
/* Mark the errno value for the thread. */
wtcb->errno = EINTR;
/* Restart the the task. */
up_unblock_task(wtcb);
}
/* Interrupts may now be enabled. */
irqrestore(saved_state);
}

View File

@@ -65,16 +65,16 @@
************************************************************/
/************************************************************
* Function: pthread_destroyjoininfo
* Function: pthread_notifywaiters
*
* Description:
* Destroy a join_t structure. This must
* be done by the child thread at child thread destruction
* time.
* Notify all other threads waiting in phread join for this
* thread's exit data. This must be done by the child
* at child thread destruction time.
*
************************************************************/
static void pthread_destroyjoininfo(FAR join_t *pjoin)
static boolean pthread_notifywaiters(FAR join_t *pjoin)
{
int ntasks_waiting;
int status;
@@ -111,14 +111,9 @@ static void pthread_destroyjoininfo(FAR join_t *pjoin)
*/
(void)pthread_takesemaphore(&pjoin->data_sem);
(void)sem_destroy(&pjoin->data_sem);
return TRUE;
}
/* All of the joined threads have had received the exit value.
* Now we can destroy this thread's exit semaphore
*/
(void)sem_destroy(&pjoin->exit_sem);
return FALSE;
}
/************************************************************
@@ -148,7 +143,6 @@ static void pthread_destroyjoininfo(FAR join_t *pjoin)
int pthread_completejoin(pid_t pid, FAR void *exit_value)
{
FAR join_t *pjoin;
boolean detached = FALSE;
dbg("process_id=%d exit_value=%p\n", pid, exit_value);
@@ -164,48 +158,72 @@ int pthread_completejoin(pid_t pid, FAR void *exit_value)
}
else
{
/* Has the thread been marked as detached? */
boolean waiters;
/* Save the return exit value in the thread structure. */
pjoin->terminated = TRUE;
detached = pjoin->detached;
if (detached)
pjoin->exit_value = exit_value;
/* Notify waiters of the availability of the exit value */
waiters = pthread_notifywaiters(pjoin);
/* If there are no waiters and if the thread is marked as detached.
* then discard the join information now. Otherwise, the pthread
* join logic will call pthread_destroyjoin() when all of the threads
* have sampled the exit value.
*/
if (!waiters && pjoin->detached)
{
dbg("Detaching\n");
/* If so, then remove the thread's structure from the private
* data set. After this point, no other thread can perform a join
* operation.
*/
(void)pthread_removejoininfo(pid);
(void)pthread_givesemaphore(&g_join_semaphore);
/* Destroy this thread data structure. */
pthread_destroyjoininfo(pjoin);
/* Deallocate the join entry if it was detached. */
sched_free((FAR void*)pjoin);
pthread_destroyjoin(pjoin);
}
/* No, then we can assume that some other thread is waiting for the join info */
/* Giving the following semaphore will allow the waiters
* to call pthread_destroyjoin.
*/
else
{
/* Save the return exit value in the thread structure. */
pjoin->exit_value = exit_value;
/* Destroy this thread data structure. */
pthread_destroyjoininfo(pjoin);
/* pthread_join may now access the thread entry structure. */
(void)pthread_givesemaphore(&g_join_semaphore);
}
(void)pthread_givesemaphore(&g_join_semaphore);
}
return OK;
}
/************************************************************
* Function: pthread_destroyjoin
*
* Description:
* This is called from pthread_completejoin if the join
* info was detached or from pthread_join when the last
* waiting thread has received the thread exit info.
*
* Or it may never be called if the join info was never
* detached or if no thread ever calls pthread_join. In
* case, there is a memory leak!
*
* Assumptions:
* The caller holds g_join_semaphore
*
************************************************************/
void pthread_destroyjoin(FAR join_t *pjoin)
{
int status;
dbg("pjoin=0x%p\n", pjoin);
/* Remove the join info from the set of joins */
(void)pthread_removejoininfo((pid_t)pjoin->thread);
/* Destroy its semaphores */
(void)sem_destroy(&pjoin->data_sem);
(void)sem_destroy(&pjoin->exit_sem);
/* And deallocate the pjoin structure */
sched_free(pjoin);
}

View File

@@ -79,7 +79,7 @@
*
* Parameters:
* argc - the number of arguments (should be 2)
* pid - the task ID of the task to wateup
* pid - the task ID of the task to wakeup
* signo - The signal to use to wake up the task
*
* Return Value:

View File

@@ -109,9 +109,7 @@ int pthread_detach(pthread_t thread)
{
/* YES.. just remove the thread entry. */
(void)pthread_removejoininfo((pid_t)thread);
sched_free(pjoin);
pjoin = NULL;
pthread_destroyjoin(pjoin);
}
else
{

View File

@@ -40,6 +40,7 @@
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include <errno.h>
#include <debug.h>
@@ -93,6 +94,17 @@ void pthread_exit(FAR void *exit_value)
dbg("exit_value=%p\n", exit_value);
/* Block any signal actions that would awaken us while were
* are performing the JOIN handshake.
*/
#ifndef CONFIG_DISABLE_SIGNALS
{
sigset_t set = ALL_SIGNAL_SET;
(void)sigprocmask(SIG_SETMASK, &set, NULL);
}
#endif
/* Complete pending join operations */
status = pthread_completejoin(getpid(), exit_value);

View File

@@ -64,6 +64,7 @@
struct join_s
{
FAR struct join_s *next; /* Implements link list */
ubyte crefs; /* Reference count */
boolean started; /* TRUE: pthread started. */
boolean detached; /* TRUE: pthread_detached'ed */
boolean terminated; /* TRUE: detach'ed+exit'ed */
@@ -115,6 +116,7 @@ extern "C" {
EXTERN void weak_function pthread_initialize(void);
EXTERN int pthread_completejoin(pid_t pid, FAR void *exit_value);
EXTERN void pthread_destroyjoin(FAR join_t *pjoin);
EXTERN FAR join_t *pthread_findjoininfo(pid_t pid);
EXTERN int pthread_givesemaphore(sem_t *sem);
EXTERN FAR join_t *pthread_removejoininfo(pid_t pid);

View File

@@ -82,12 +82,13 @@
*
* Return Value:
* 0 if successful. Otherwise, one of the following error codes:
* EINVAL The value specified by thread does not refer to a
* joinable thread.
* ESRCH No thread could be found corresponding to that
* specified by the given thread ID.
* EDEADLK A deadlock was detected or the value of thread
* specifies the calling thread.
*
* EINVAL The value specified by thread does not refer to a
* joinable thread.
* ESRCH No thread could be found corresponding to that
* specified by the given thread ID.
* EDEADLK A deadlock was detected or the value of thread
* specifies the calling thread.
*
* Assumptions:
*
@@ -144,74 +145,99 @@ int pthread_join(pthread_t thread, pthread_addr_t *pexit_value)
* case, it must be a task and not a pthread.
*/
else /* if ((tcb->flags & EDEADLK) == 0) */
else
{
ret = EINVAL;
}
(void)pthread_givesemaphore(&g_join_semaphore);
}
else if (pjoin->terminated)
{
dbg("Thread has terminated\n");
/* Get the thread exit value from the terminated thread. */
if (pexit_value)
{
dbg("exit_value=0x%p\n", pjoin->exit_value);
*pexit_value = pjoin->exit_value;
}
/* Then remove and deallocate the thread entry. */
(void)pthread_removejoininfo((pid_t)thread);
(void)pthread_givesemaphore(&g_join_semaphore);
sched_free(pjoin);
ret = OK;
}
else
{
dbg("Thread is still running\n");
/* Relinquish the data set semaphore, making certain that
* no task has the opportunity to run between the time
* we relinquish the data set semaphore and the time that
* we wait on the join semaphore.
/* We found the join info structure. Increment for the reference
* to the join structure that we have. This will keep things
* stable for we have to do
*/
sched_lock();
(void)pthread_givesemaphore(&g_join_semaphore);
pjoin->crefs++;
/* Take the thread's join semaphore */
(void)pthread_takesemaphore(&pjoin->exit_sem);
/* Get the thread exit value */
if (pexit_value)
{
*pexit_value = pjoin->exit_value;
dbg("exit_value=0x%p\n", pjoin->exit_value);
}
/* Then remove the thread entry. */
(void)pthread_removejoininfo((pid_t)thread);
/* Post the thread's join semaphore so that exitting thread
* will know that we have received the data.
/* Check if the thread is still running. If not, then things are
* simpler. There are still race conditions to be concerned with.
* For example, there could be multiple threads executing in the
* 'else' block below when we enter!
*/
(void)pthread_givesemaphore(&pjoin->data_sem);
if (pjoin->terminated)
{
dbg("Thread has terminated\n");
/* Pre-emption is okay now. */
/* Get the thread exit value from the terminated thread. */
if (pexit_value)
{
dbg("exit_value=0x%p\n", pjoin->exit_value);
*pexit_value = pjoin->exit_value;
}
}
else
{
dbg("Thread is still running\n");
/* Relinquish the data set semaphore. Since pre-emption is
* disabled, we can be certain that no task has the
* opportunity to run between the time we relinquish the
* join semaphore and the time that we wait on the thread exit
* semaphore.
*/
(void)pthread_givesemaphore(&g_join_semaphore);
/* Take the thread's thread exit semaphore. We will sleep here
* until the thread exits. We need to exercise caution because
* there could be multiple threads waiting here for the same
* pthread to exit.
*/
(void)pthread_takesemaphore(&pjoin->exit_sem);
/* The thread has exited! Get the thread exit value */
if (pexit_value)
{
*pexit_value = pjoin->exit_value;
dbg("exit_value=0x%p\n", pjoin->exit_value);
}
/* Post the thread's data semaphore so that the exitting thread
* will know that we have received the data.
*/
(void)pthread_givesemaphore(&pjoin->data_sem);
/* Retake the join semaphore, we need to hold this when
* pthread_destroyjoin is called.
*/
(void)pthread_takesemaphore(&g_join_semaphore);
}
/* Pre-emption is okay now. The logic still cannot be re-entered
* because we hold the join semaphore
*/
sched_unlock();
/* Deallocate the thread entry */
/* Release our reference to the join structure and, if the reference
* count decrements to zero, deallocate the join structure.
*/
if (--pjoin->crefs <= 0)
{
(void)pthread_destroyjoin(pjoin);
}
(void)pthread_givesemaphore(&g_join_semaphore);
sched_free(pjoin);
ret = OK;
}

View File

@@ -156,11 +156,13 @@ int sem_wait(sem_t *sem)
/* Add the TCB to the prioritized semaphore wait queue */
*get_errno_ptr() = 0;
up_block_task(rtcb, TSTATE_WAIT_SEM);
/* When we resume at this point, either (1) the semaphore has been
* assigned to this thread of execution, or (2) the semaphore wait
* has been interrupted by a signal.
* has been interrupted by a signal. We can detect the latter case
* be examining the errno value.
*/
if (*get_errno_ptr() != EINTR)

View File

@@ -47,6 +47,7 @@
#include "os_internal.h"
#include "sem_internal.h"
#include "sig_internal.h"
#include "mq_internal.h"
/************************************************************
* Definitions
@@ -288,8 +289,8 @@ int sig_received(FAR _TCB *stcb, siginfo_t *info)
irqstate_t saved_state;
int ret = ERROR;
dbg("sig_received: TCB=0x%08x signo=%d code=%d value=%d\n",
stcb, info->si_signo, info->si_code, info->si_value.sival_int);
dbg("sig_received: TCB=0x%08x signo=%d code=%d value=%d mask=%08x\n",
stcb, info->si_signo, info->si_code, info->si_value.sival_int, stcb->sigprocmask);
if (stcb && info)
{
@@ -362,25 +363,32 @@ int sig_received(FAR _TCB *stcb, siginfo_t *info)
/* If the task neither was waiting for the signal nor had a signal
* handler attached to the signal, then the default action is
* simply to ignore the signal */
}
* simply to ignore the signal
*/
/****** OTHER SIGNAL HANDLING ******/
/****** OTHER SIGNAL HANDLING ******/
/* If the task is blocked waiting for a semaphore, then that
* task must be unblocked when a signal is received.
*/
/* If the task is blocked waiting for a semaphore, then that
* task must be unblocked when a signal is received.
*/
if (stcb->task_state == TSTATE_WAIT_SEM)
{
sem_waitirq(stcb);
}
if (stcb->task_state == TSTATE_WAIT_SEM)
{
sem_waitirq(stcb);
}
/* If the task is blocked waiting on a message queue, then that
* task must be unblocked when a signal is received.
*/
/* If the task is blocked waiting on a message queue, then that
* task must be unblocked when a signal is received.
*/
/* NOT YET IMPLEMENTED. */
#ifndef CONFIG_DISABLE_MQUEUE
if (stcb->task_state == TSTATE_WAIT_MQNOTEMPTY ||
stcb->task_state == TSTATE_WAIT_MQNOTFULL)
{
mq_waitirq(stcb);
}
#endif
}
}
return ret;

View File

@@ -118,10 +118,12 @@ STATUS task_delete(pid_t pid)
/* Make sure the task does not become ready-to-run while
* we are futzing with its TCB by locking ourselves as the
* executing task.
*
* Frist, find for the TCB associated with matching pid
*/
sched_lock();
/* Find for the TCB associated with matching pid */
dtcb = sched_gettcb(pid);
if (!dtcb)
{

View File

@@ -187,11 +187,18 @@ STATUS task_schedsetup(FAR _TCB *tcb, int priority,
tcb->start = start;
tcb->entry.main = main;
/* Initialize other (non-zero) elements of the TCB */
/* exec() and pthread_create() inherit the signal mask of the
* parent thread. I suppose that task_create() should as well.
*/
#ifndef CONFIG_DISABLE_SIGNALS
tcb->sigprocmask = ALL_SIGNAL_SET;
(void)sigprocmask(SIG_SETMASK, NULL, &tcb->sigprocmask);
#endif
/* Initialize the task state. It does not get a valid state
* until it is activated.
*/
tcb->task_state = TSTATE_TASK_INVALID;
/* Initialize the processor-specific portion of the TCB */