sched/wqueue, libs/libc/wqueue, configs: Remove work queue polling delay to simplify the code logic and save the power.

This commit is contained in:
xuanlin
2018-08-25 14:58:07 -06:00
committed by Gregory Nutt
parent 631071cded
commit 7e63b0b288
30 changed files with 82 additions and 184 deletions
+28 -35
View File
@@ -12,7 +12,7 @@
<h1><big><font color="#3c34ec">
<i>NuttX RTOS Porting Guide</i>
</font></big></h1>
<p>Last Updated: August 10, 2018</p>
<p>Last Updated: August 25, 2018</p>
</td>
</tr>
</table>
@@ -3009,10 +3009,18 @@ typedef uint32_t wdparm_t;
The dedicated high-priority work queue is intended to handle delayed processing from interrupt handlers. This work queue is required for some drivers but, if there are no complaints, can be safely disabled. The high priority worker thread also performs garbage collection -- completing any delayed memory deallocations from interrupt handlers. If the high-priority worker thread is disabled, then that clean up will be performed either by (1) the low-priority worker thread, if enabled, and if not (2) the IDLE thread instead (which runs at the lowest of priority and may not be appropriate if memory reclamation is of high priority)
</p>
<p><b>Device Driver Bottom Half</b>.
The higher priority worker thread is intended to serve as the <i>bottom half</i> for device drivers. As a consequence it must run at a very high, fixed priority rivalling the priority of the interrupt handler itself. Typically, the high priority work queue should be the highest priority thread in your system (the default priority is 224).
The high-priority worker thread is intended to serve as the <i>bottom half</i> for device drivers. As a consequence it must run at a very high, fixed priority rivalling the priority of the interrupt handler itself. Typically, the high priority work queue should be the highest priority thread in your system (the default priority is 224).
</p>
<p>
<b>Thread Pool</b>.
The work queues can be configured to support multiple, low-priority threads. This is essentially a <i>thread pool</i> that provides multi-threaded servicing of the queue work. This breaks the strict serialization of the &quot;queue&quot; (and hence, the work queue is no longer a queue at all).
</p>
<p>
Multiple worker threads are required to support, for example, I/O operations that stall waiting for input. If there is only a single thread, then the entire work queue processing would stall in such cases.
Such behavior is necessary to support asynchronous I/O, AIO, for example.
</p>
<p><b>Compared to the Low Priority Kernel Work Queue</b>.
For less critical, lower priority, application oriented worker thread support, consider enabling the lower priority work queue. The lower priority work queue runs at a lower priority, of course, but has the added advantage that it supports <i>priority inheritance</i> (if &lt;config&gt; CONFIG_PRIORITY_INHERITANCE</code> is also selected): The priority of the lower priority worker thread can then be adjusted to match the highest priority client.
For less critical, lower priority, application oriented worker thread support, consider enabling the lower priority work queue. The lower priority work queue runs at a lower priority, of course, but has the added advantage that it supports <i>priority inheritance</i> (if <code>CONFIG_PRIORITY_INHERITANCE=y</code> is also selected): The priority of the lower priority worker thread can then be adjusted to match the highest priority client.
</p>
<p>
<b>Configuration Options</b>.
@@ -3021,11 +3029,12 @@ typedef uint32_t wdparm_t;
<li><code>CONFIG_SCHED_HPWORK</code>.
Enables the hight priority work queue.
</li>
<li><code>CONFIG_SCHED_HPNTHREADS</code>.
The number of threads in the high-priority queue's thread pool. Default: 1
</li>
<li><code>CONFIG_SCHED_HPWORKPRIORITY</code>.
The execution priority of the high-priority worker thread. Default: 224
</li>
<li><code>CONFIG_SCHED_HPWORKPERIOD</code>.
How often the worker thread re-checks for work in units of microseconds. This work period is really only necessary if the high priority thread is performing periodic garbage collection. The worker thread will be awakened immediately with it is queued work to be done. If the high priority worker thread is performing garbage collection, then the default is 50*1000 (50 MS). Otherwise, if the lower priority worker thread is performing garbage collection, the default is 100*1000.
<li><code>CONFIG_SCHED_HPWORKSTACKSIZE</code>.
The stack size allocated for the worker thread in bytes. Default: 2048.
</li>
@@ -3047,30 +3056,19 @@ typedef uint32_t wdparm_t;
</p>
<p>
<b>Compared to the High Priority Work Queue</b>.
The lower priority work queue runs at a lower priority than the high priority work queue, of course, and so is inappropriate to serve as a driver <i>bottom half</i>. The lower priority work queue has the other advantages, however, that make it better suited for some tasks:
The lower priority work queue runs at a lower priority than the high priority work queue, of course, and so is inappropriate to serve as a driver <i>bottom half</i>.
It is, otherwise, very similar to the high priority work queue and most of the discussion above for the high priority work queue applies equally here.
The lower priority work queue does have one important, however, that make it better suited for some tasks:
</p>
<p><b>Priority Inheritance</b>.
The lower priority worker thread(s) support <i>priority inheritance</i> (if &lt;config&gt; CONFIG_PRIORITY_INHERITANCE</code> is also selected): The priority of the lower priority worker thread can then be adjusted to match the highest priority client.
</p>
<blockquote>
<b>NOTE:</b> This priority inheritance feature is not automatic. The lower priority worker thread will always a fixed priority unless additional logic implements that calls <code>lpwork_boostpriority()</code> to raise the priority of the lower priority worker thread (typically called before scheduling the work) and then calls the matching <code>lpwork_restorepriority()</code> when the work is completed (typically called within the work handler at the completion of the work). Currently, only the NuttX asynchronous I/O logic uses this dynamic prioritization feature.
</blockquote>
<p>
The higher priority worker thread, on the other hand, is intended to serve as the <i>bottom half</i> for device drivers. As a consequence must run at a very high, fixed priority. Typically, it should be the highest priority thread in your system.
</p>
<ul>
<li>
<p><b>Priority Inheritance</b>.
The lower priority worker thread(s) support <i>priority inheritance</i> (if &lt;config&gt; CONFIG_PRIORITY_INHERITANCE</code> is also selected): The priority of the lower priority worker thread can then be adjusted to match the highest priority client.
</p>
<blockquote>
<b>NOTE:</b> This priority inheritance feature is not automatic. The lower priority worker thread will always a fixed priority unless additional logic implements that calls <code>lpwork_boostpriority()</code> to raise the priority of the lower priority worker thread (typically called before scheduling the work) and then calls the matching <code>lpwork_restorepriority()</code> when the work is completed (typically called within the work handler at the completion of the work). Currently, only the NuttX asynchronous I/O logic uses this dynamic prioritization feature.
</blockquote>
<p>
The higher priority worker thread, on the other hand, is intended to serve as the <i>bottom half</i> for device drivers. As a consequence must run at a very high, fixed priority. Typically, it should be the highest priority thread in your system.
</p>
</li>
<li>
<p>
<b>Thread Pool</b>.
The low-priority work queue can be configured to support multiple, low-priority threads. This is essentially a <i>thread pool</i> that provides multi-threaded servicing of the low-priority work thread. This breaks the strict serialization of the &quot;queue&quot; (and hence, the low-priority work queue is no longer a queue at all).
</p>
<p>
Multiple worker threads are required to support, for example, I/O operations that stall waiting for input. If there is only a single thread, then the entire low-priority queue processing would stall in such cases. Such behavior is necessary to support asynchronous I/O, AIO, for example.
</p>
</li>
</ul>
<p>
<b>Configuration Options</b>.
</p>
@@ -3079,16 +3077,13 @@ typedef uint32_t wdparm_t;
If CONFIG_SCHED_LPWORK is selected then a lower-priority work queue will be enabled.
</li>
<li><code>CONFIG_SCHED_LPNTHREADS</code>.
The number of thread in the low-priority queue's thread pool. Default: 1
The number of threads in the low-priority queue's thread pool. Default: 1
</li>
<li><code>CONFIG_SCHED_LPWORKPRIORITY</code>.
The minimum execution priority of the lower priority worker thread. The priority of the all worker threads start at this priority. If priority inheritance is in effect, the priority may be boosted from this level. Default: 50.
</li>
<li><code>CONFIG_SCHED_LPWORKPRIOMAX</code>.
The maximum execution priority of the lower priority worker thread. Lower priority worker threads will be started at <code>CONFIG_SCHED_LPWORKPRIORITY</code> but their priority may be boosted due to priority inheritance. The boosted priority of the low priority worker thread will not, however, ever exceed<code>CONFIG_SCHED_LPWORKPRIOMAX</code>. This limit would be necessary, for example, if the higher priority worker thread were to defer work to the lower priority thread. Clearly, in such a case, you would want to limit the maximum priority of the lower priority work thread. Default: 176.
</li>
<li><code>CONFIG_SCHED_LPWORKPERIOD</code>.
How often the lower priority worker thread checks for garbage collection in units of microseconds. Default: 50*1000 (50 MS).
The maximum execution priority of the lower priority worker thread. Lower priority worker threads will be started at <code>CONFIG_SCHED_LPWORKPRIORITY</code> but their priority may be boosted due to priority inheritance. The boosted priority of the low priority worker thread will not, however, ever exceed <code>CONFIG_SCHED_LPWORKPRIOMAX</code>. This limit would be necessary, for example, if the higher priority worker thread were to defer work to the lower priority thread. Clearly, in such a case, you would want to limit the maximum priority of the lower priority work thread. Default: 176.
</li>
<li><code>CONFIG_SCHED_LPWORKSTACKSIZE</code>.
The stack size allocated for the lower priority worker thread. Default: 2048.
@@ -3112,8 +3107,6 @@ typedef uint32_t wdparm_t;
If CONFIG_LIB_USRWORK is also defined then the user-mode work queue will be enabled.
<li><code>CONFIG_LIB_USRWORKPRIORITY</code>.
The execution priority of the user-mode priority worker thread. Default: 100
<li><code>CONFIG_LIB_USRWORKPERIOD</code>
How often the lower priority worker thread is awakened in units of microseconds. Default: 100*1000 (100 MS).
<li><code>CONFIG_LIB_USRWORKSTACKSIZE</code>.
The stack size allocated for the lower priority worker thread. Default: 2048.
</ul>