未验证 提交 3704741e 编写于 作者: O openharmony_ci 提交者: Gitee

!14350 [翻译完成】#I6863P

Merge pull request !14350 from Annie_wang/PR12243
# Events
# Event
## Basic Concepts
An event is a mechanism for communication between tasks. It can be used to synchronize tasks. The events have the following features:
An event is a communication mechanism used to synchronize tasks. Events have the following features:
- Events can be synchronized in one-to-many or many-to-many mode. In one-to-many mode, a task can wait for multiple events. In many-to-many mode, multiple tasks can wait for multiple events. However, a write event wakes up only one task from the block.
- Event read timeout mechanism is used.
- Events are used only for task synchronization, but not for data transmission.
- Events are used for task synchronization, but not for data transmission.
APIs are provided to initialize, read/write, clear, and destroy events.
......@@ -18,7 +18,7 @@ APIs are provided to initialize, read/write, clear, and destroy events.
### Event Control Block
The event control block is a struct configured in the event initialization function. It is passed in as an input parameter to identify the event for operations such as event read and write. The data structure of the event control block is as follows:
The event control block is a structure in the event initialization function. It passes in event identifies for operations such as event read and write. The data structure of the event control block is as follows:
```
......@@ -31,23 +31,33 @@ typedef struct tagEvent {
### Working Principles
**Initializing an event**: An event control block is created to maintain a collection of processed events and a linked list of tasks waiting for specific events.
**Initializing an Event**
**Writing an event**: When a specified event is written to the event control block, the event control block updates the event set, traverses the task linked list, and determines whether to wake up related task based on the task conditions.
An event control block is created to maintain a set of processed events and a linked list of tasks waiting for specific events.
**Reading an event**: If the read event already exists, it is returned synchronously. In other cases, the return time is determined based on the timeout period and event triggering status. If the wait event condition is met before the timeout period expires, the blocked task will be directly woken up. Otherwise, the blocked task will be woken up only after the timeout period has expired.
**Writing an Event**
The input parameters **eventMask** and **mode** determine whether the condition for reading an event is met. **eventMask** indicates the mask of the event. **mode** indicates the handling mode, which can be any of the following:
When an event is written to the event control block, the event control block updates the event set, traverses the task linked list, and determines whether to wake up related tasks based on the task conditions.
- **LOS_WAITMODE_AND**: Event reading is successful only when all the events corresponding to **eventMask** occur. Otherwise, the task will be blocked, or an error code will be returned.
**Reading an Event**
- **LOS_WAITMODE_OR**: Event reading is successful when any of the events corresponding to **eventMask** occur. Otherwise, the task will be blocked, or an error code will be returned.
If the event to read already exists, it is returned synchronously. In other cases, the event is returned based on the timeout period and event triggering conditions. If the wait condition is met before the timeout period expires, the blocked task will be directly woken up. Otherwise, the blocked task will be woken up only after the timeout period has expired.
The parameters **eventMask** and **mode** determine whether the condition for reading an event is met. **eventMask** specifies the event mask. **mode** specifies the handling mode, which can be any of the following:
- **LOS_WAITMODE_AND**: Read the event only when all the events corresponding to **eventMask** occur. Otherwise, the task will be blocked, or an error code will be returned.
- **LOS_WAITMODE_OR**: Read the event only when any of the events corresponding to **eventMask** occur. Otherwise, the task will be blocked, or an error code will be returned.
- **LOS_WAITMODE_CLR**: This mode must be used with one or all of the event modes (LOS_WAITMODE_AND | LOS_WAITMODE_CLR or LOS_WAITMODE_OR | LOS_WAITMODE_CLR). In this mode, if all event modes or any event mode is successful, the corresponding event type bit in the event control block will be automatically cleared.
**Clearing events**: Clear the event set of the event control block based on the specified mask. If the mask is **0**, the event set will be cleared. If the mask is **0xffff**, no event will be cleared, and the event set remains unchanged.
**Clearing Events**
The events in the event set of the event control block can be cleared based on the specified mask. The mask **0** means to clear the event set; the mask **0xffff** means the opposite.
**Destroying Events**
**Destroying an event**: Destroy the specified event control block.
The event control block can be destroyed to release resources.
**Figure 1** Event working mechanism for a mini system
......@@ -58,12 +68,12 @@ The input parameters **eventMask** and **mode** determine whether the condition
| Category| API| Description|
| -------- | -------- | -------- |
| Event check| LOS_EventPoll | Checks whether the expected event occurs based on **eventID**, **eventMask**, and **mode**.<br>**NOTICE**<br><br>If **mode** contains **LOS_WAITMODE_CLR** and the expected event occurs, the event that meets the requirements in **eventID** will be cleared. In this case, **eventID** is an input parameter and an output parameter. In other cases, **eventID** is used only as an input parameter.|
| Initialization| LOS_EventInit | Initializes an event control block.|
| Event read| LOS_EventRead | Reads an event (wait event). The task will be blocked to wait based on the timeout period (in ticks).<br>If no event is read, **0** is returned.<br>If an event is successfully read, a positive value (event set) is returned.<br>In other cases, an error code is returned.|
| Event write| LOS_EventWrite | Writes an event to the event control block.|
| Event clearance| LOS_EventClear | Clears an event in the event control block based on the event mask.|
| Event destruction| LOS_EventDestroy | Destroys an event control block.|
| Checking an event | LOS_EventPoll | Checks whether the expected event occurs based on **eventID**, **eventMask**, and **mode**.<br>**NOTE**<br>If **mode** contains **LOS_WAITMODE_CLR** and the expected event occurs, the event that meets the requirements in **eventID** will be cleared. In this case, **eventID** is an input parameter and an output parameter. In other cases, **eventID** is used only as an input parameter. |
| Initializing an event control block | LOS_EventInit | Initializes an event control block.|
| Reading an event | LOS_EventRead | Reads an event (wait event). The task will be blocked to wait based on the timeout period (in ticks).<br>If no event is read, **0** is returned.<br>If an event is successfully read, a positive value (event set) is returned.<br>In other cases, an error code is returned.|
| Writing an event | LOS_EventWrite | Writes an event to the event control block.|
| Clearing events | LOS_EventClear | Clears events in the event control block based on the event mask. |
| Destroying events | LOS_EventDestroy | Destroys an event control block.|
## How to Develop
......@@ -72,11 +82,11 @@ The typical event development process is as follows:
1. Initialize an event control block.
2. Block a read event control block.
2. Block a read event.
3. Write related events.
3. Write events.
4. Wake up a blocked task, read the event, and check whether the event meets conditions.
4. Wake up the blocked task, read the event, and check whether the event meets conditions.
5. Handle the event control block.
......@@ -84,7 +94,7 @@ The typical event development process is as follows:
> **NOTE**
> - When an event is read or written, the 25th bit of the event is reserved and cannot be set.
> - For event read and write operations, the 25th bit (`0x02U << 24`) of the event is reserved and cannot be set.
>
> - Repeated writes of the same event are treated as one write.
......@@ -111,7 +121,7 @@ In the **ExampleEvent** task, create an **EventReadTask** task with a timout per
The sample code is as follows:
The sample code is compiled and verified in **./kernel/liteos_m/testsuites/src/osTest.c**. Call **ExampleEvent()** in **TestTaskEntry**.
The sample code can be compiled and verified in **./kernel/liteos_m/testsuites/src/osTest.c**. The **ExampleEvent()** function is called in **TestTaskEntry**.
```
......
......@@ -77,7 +77,7 @@ The preceding figure illustrates how to write data to the tail node only. Writin
## Available APIs
| Category| Description|
| Category| API Description |
| -------- | -------- |
| Creating or deleting a message queue| **LOS_QueueCreate**: creates a message queue. The system dynamically allocates the queue space.<br>**LOS_QueueCreateStatic**: creates a static message queue. You need to pass in the queue space.<br>**LOS_QueueDelete**: deletes a message queue. After a static message queue is deleted, you need to release the queue space.|
| Reading or writing data (address without the content) in a queue| **LOS_QueueRead**: reads data in the head node of the specified queue. The data in the queue node is an address.<br>**LOS_QueueWrite**: writes the **bufferAddr** (buffer address) to the tail node of the specified queue.<br>**LOS_QueueWriteHead**: writes the **bufferAddr** (buffer address) to the head node of the specified queue.|
......@@ -136,7 +136,7 @@ Create a queue and two tasks. Enable task 1 to write data to the queue, and task
The sample code is as follows:
The sample code is compiled and verified in **./kernel/liteos_m/testsuites/src/osTest.c**. Call **ExampleQueue** in **TestTaskEntry**.
The sample code can be compiled and verified in **./kernel/liteos_m/testsuites/src/osTest.c**. The **ExampleQueue** function is called in **TestTaskEntry**.
```
......
# Bitwise Operation
## Basic Concepts
A bitwise operation operates on a binary number at the level of its individual bits. For example, a variable can be set as a program status word \(PSW\), and each bit \(flag bit\) in the PSW can have a self-defined meaning.
## Available APIs<a name="section848334511411"></a>
The system provides operations for setting the flag bit to **1** or **0**, changing the flag bit content, and obtaining the most significant bit and least significant bit of the flag bit 1 in a PSW. You can also perform bitwise operations on system registers. The following table describes the APIs available for the bitwise operation module. For more details about the APIs, see the API reference.
**Table 1** Bitwise operation module APIs
<a name="table148791521769"></a>
<table><thead align="left"><tr id="row13880624615"><th class="cellrowborder" valign="top" width="16.89168916891689%" id="mcps1.2.4.1.1"><p id="p1587119571763"><a name="p1587119571763"></a><a name="p1587119571763"></a>Function</p>
</th>
<th class="cellrowborder" valign="top" width="35.54355435543554%" id="mcps1.2.4.1.2"><p id="p38714577610"><a name="p38714577610"></a><a name="p38714577610"></a>API</p>
</th>
<th class="cellrowborder" valign="top" width="47.56475647564757%" id="mcps1.2.4.1.3"><p id="p108711657563"><a name="p108711657563"></a><a name="p108711657563"></a>Description</p>
</th>
</tr>
</thead>
<tbody><tr id="row18801722069"><td class="cellrowborder" rowspan="2" valign="top" width="16.89168916891689%" headers="mcps1.2.4.1.1 "><p id="p108717579612"><a name="p108717579612"></a><a name="p108717579612"></a>Setting the flag bit to <strong id="b129301229122320"><a name="b129301229122320"></a><a name="b129301229122320"></a>1</strong> or <strong id="b1899463182312"><a name="b1899463182312"></a><a name="b1899463182312"></a>0</strong></p>
</td>
<td class="cellrowborder" valign="top" width="35.54355435543554%" headers="mcps1.2.4.1.2 "><p id="p88717574616"><a name="p88717574616"></a><a name="p88717574616"></a>LOS_BitmapSet</p>
</td>
<td class="cellrowborder" valign="top" width="47.56475647564757%" headers="mcps1.2.4.1.3 "><p id="p16871957668"><a name="p16871957668"></a><a name="p16871957668"></a>Sets a flag bit of a PSW to <strong id="b1283195411179"><a name="b1283195411179"></a><a name="b1283195411179"></a>1</strong>.</p>
</td>
</tr>
<tr id="row38805219612"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p68713574610"><a name="p68713574610"></a><a name="p68713574610"></a>LOS_BitmapClr</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p14871155718618"><a name="p14871155718618"></a><a name="p14871155718618"></a>Sets a flag bit of a PSW to <strong id="b15267438112312"><a name="b15267438112312"></a><a name="b15267438112312"></a>0</strong>.</p>
</td>
</tr>
<tr id="row16880112663"><td class="cellrowborder" rowspan="2" valign="top" width="16.89168916891689%" headers="mcps1.2.4.1.1 "><p id="p158710579615"><a name="p158710579615"></a><a name="p158710579615"></a>Obtaining the bit whose flag bit is <strong id="b58742415239"><a name="b58742415239"></a><a name="b58742415239"></a>1</strong></p>
</td>
<td class="cellrowborder" valign="top" width="35.54355435543554%" headers="mcps1.2.4.1.2 "><p id="p1787145718612"><a name="p1787145718612"></a><a name="p1787145718612"></a>LOS_HighBitGet</p>
</td>
<td class="cellrowborder" valign="top" width="47.56475647564757%" headers="mcps1.2.4.1.3 "><p id="p168713571468"><a name="p168713571468"></a><a name="p168713571468"></a>Obtains the most significant bit of <strong id="b485014714235"><a name="b485014714235"></a><a name="b485014714235"></a>1</strong> in the PSW.</p>
</td>
</tr>
<tr id="row138803219613"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p15871957467"><a name="p15871957467"></a><a name="p15871957467"></a>LOS_LowBitGet</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p148719571569"><a name="p148719571569"></a><a name="p148719571569"></a>Obtains the least significant bit of <strong id="b9907125542319"><a name="b9907125542319"></a><a name="b9907125542319"></a>1</strong> in the PSW.</p>
</td>
</tr>
<tr id="row0880182168"><td class="cellrowborder" rowspan="3" valign="top" width="16.89168916891689%" headers="mcps1.2.4.1.1 "><p id="p10871957265"><a name="p10871957265"></a><a name="p10871957265"></a>Operating continuous bits</p>
</td>
<td class="cellrowborder" valign="top" width="35.54355435543554%" headers="mcps1.2.4.1.2 "><p id="p787185717616"><a name="p787185717616"></a><a name="p787185717616"></a>LOS_BitmapSetNBits</p>
</td>
<td class="cellrowborder" valign="top" width="47.56475647564757%" headers="mcps1.2.4.1.3 "><p id="p10871135714613"><a name="p10871135714613"></a><a name="p10871135714613"></a>Sets the continuous flag bits of a PSW to <strong id="b145631313234"><a name="b145631313234"></a><a name="b145631313234"></a>1</strong>.</p>
</td>
</tr>
<tr id="row12881728619"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p18710575615"><a name="p18710575615"></a><a name="p18710575615"></a>LOS_BitmapClrNBits</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1387145711610"><a name="p1387145711610"></a><a name="p1387145711610"></a>Sets the continuous flag bits of a PSW to <strong id="b185031722103115"><a name="b185031722103115"></a><a name="b185031722103115"></a>0</strong>.</p>
</td>
</tr>
<tr id="row4881192262"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1987155714611"><a name="p1987155714611"></a><a name="p1987155714611"></a>LOS_BitmapFfz</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p187115571369"><a name="p187115571369"></a><a name="p187115571369"></a>Obtains the first 0 bit starting from the least significant bit (LSB).</p>
</td>
</tr>
</tbody>
</table>
## Development Example<a name="section67569495514"></a>
### Example Description<a name="section33551554391"></a>
A bitwise operation operates on the bits of a binary number. A variable can be set as a program status word (PSW), and each bit (flag bit) in the PSW can have a self-defined meaning.
## **Available APIs**
The system provides operations for setting the flag bit to **1** or **0**, changing the flag bit content, and obtaining the most significant bit (MSB) and least significant bit (LSB) of the flag bit 1 in a PSW. You can also perform bitwise operations on system registers. The following table describes the APIs available for the bitwise operation module. For more details about the APIs, see the API reference.
**Table 1** APIs of the bitwise operation module
| Category | API Description |
| -------- | -------- |
| Setting a flag bit| - **LOS_BitmapSet**: sets a flag bit of a PSW to **1**.<br>- **LOS_BitmapClr**: sets a flag bit of a PSW to **0**. |
| Obtaining the bit whose flag bit is **1**| -**LOS_HighBitGet**: obtains the most significant bit of 1 in a PSW.<br>- **LOS_LowBitGet**: obtains the least significant bit of 1 in a PSW. |
| Operating continuous bits| - **LOS_BitmapSetNBits**: sets the consecutive flag bits of a PSW to **1**.<br>- **LOS_BitmapClrNBits**: sets the consecutive flag bits of a PSW to **0**.<br>- **LOS_BitmapFfz**: obtains the first 0 bit starting from the LSB. |
## Development Example
### Example Description
This example implements the following:
1. Set a flag bit to **1**.
2. Obtain the most significant bit of flag bit 1.
2. Obtain the MSB of flag bit 1.
3. Set a flag bit to **0**.
4. Obtain the least significant bit of the flag bit 1.
4. Obtain the LSB of flag bit 1.
### Sample Code
The sample code can be compiled and verified in **./kernel/liteos_a/testsuites/kernel/src/osTest.c**. The **BitSample** function is called in **TestTaskEntry**.
```
#include "los_bitmap.h"
......@@ -105,10 +67,12 @@ static UINT32 BitSample(VOID)
}
```
### Verification
The development is successful if the return result is as follows:
```
Bitmap Sample!
The flag is 0x10101010
......@@ -117,4 +81,3 @@ LOS_HighBitGet:The highest one bit is 28, the flag is 0x10101110
LOS_BitmapClr: pos : 28, the flag is 0x00101110
LOS_LowBitGet: The lowest one bit is 4, the flag is 0x00101110
```
......@@ -8,19 +8,18 @@ A doubly linked list (DLL) is a linked data structure that consists of a set of
## Available APIs
The table below describes the DLL APIs. For more details about the APIs, see the API reference.
| **Category**| **API**|
| -------- | -------- |
| Initializing a DLL| - **LOS_ListInit**: initializes a node as a DLL node.<br>- **LOS_DL_LIST_HEAD**: defines a node and initializes it as a DLL node.|
| Adding a node| - **LOS_ListAdd**: adds a node to the head of a DLL.<br>- **LOS_ListHeadInsert**: same as **LOS_ListAdd**.<br>- **LOS_ListTailInsert**: inserts a node to the tail of a DLL.|
| Adding a DLL| - **LOS_ListAddList**: adds the head of a DLL to the head of this DLL.<br>- **LOS_ListHeadInsertList**: inserts the head of a DLL to the head of this DLL.<br>- **LOS_ListTailInsertList**: Inserts the end of a DLL to the head of this DLL.|
| Deleting a node| - **LOS_ListDelete**: deletes a node from this DLL.<br>- **LOS_ListDelInit**: deletes a node from this DLL and uses this node to initialize the DLL.|
| Checking a DLL| - **LOS_ListEmpty**: checks whether a DLL is empty.<br>- **LOS_DL_LIST_IS_END**: checks whether a node is the tail of the DLL.<br>- **LOS_DL_LIST_IS_ON_QUEUE**: checks whether a node is in the DLL.|
| Obtains structure information.| - **LOS_OFF_SET_OF**: obtains the offset of a member in the specified structure relative to the start address of the structure.<br>- **LOS_DL_LIST_ENTRY**: obtains the address of the structure that contains the first node in the DLL. The first input parameter of the API indicates the head node in the list, the second input parameter indicates the name of the structure to be obtained, and the third input parameter indicates the name of the linked list in the structure.<br>- **LOS_ListPeekHeadType**: obtains the address of the structure that contains the first node in the linked list. The first input parameter of the API indicates the head node in the list, the second input parameter indicates the name of the structure to be obtained, and the third input parameter indicates the name of the linked list in the structure. Null will be returned if the DLL is empty.<br>- **LOS_ListRemoveHeadType**: obtains the address of the structure that contains the first node in the linked list, and deletes the first node from the list. The first input parameter of the API indicates the head node in the list, the second input parameter indicates the name of the structure to be obtained, and the third input parameter indicates the name of the linked list in the structure. Null will be returned if the DLL is empty.<br>- **LOS_ListNextType**: obtains the address of the structure that contains the next node of the specified node in the linked list. The first input parameter of the API indicates the head node in the list, the second input parameter indicates the specified node, the third parameter indicates the name of the structure to be obtained, and the fourth input parameter indicates the name of the linked list in the structure. If the next node of the linked list node is the head node and is empty, NULL will be returned.|
| Traversing a DLL| - **LOS_DL_LIST_FOR_EACH**: traverses a DLL.<br>- **LOS_DL_LIST_FOR_EACH_SAFE**: traverses the DLL and stores the subsequent nodes of the current node for security verification.|
| Traversing the structure that contains the DLL| - **LOS_DL_LIST_FOR_EACH_ENTRY**: traverses a DLL and obtains the address of the structure that contains the linked list node.<br>- **LOS_DL_LIST_FOR_EACH_ENTRY_SAFE**: traverses a DLL, obtains the address of the structure that contains the linked list node, and stores the address of the structure that contains the subsequent node of the current node.|
The table below describes APIs available for the DLL. For more details about the APIs, see the API reference.
| Category | API Description |
| ------------------------ | ------------------------------------------------------------ |
| Initializing a DLL | - **LOS_ListInit**: initializes a node as a DLL node.<br>- **LOS_DL_LIST_HEAD**: defines a node and initializes it as a DLL node.|
| Adding a node | - **LOS_ListAdd**: adds a node to the head of a DLL.<br>- **LOS_ListHeadInsert**: same as **LOS_ListAdd**.<br>- **LOS_ListTailInsert**: inserts a node to the tail of a DLL.|
| Adding a DLL | - **LOS_ListAddList**: adds the head of a DLL to the head of this DLL.<br>- **LOS_ListHeadInsertList**: inserts the head of a DLL to the head of this DLL.<br>- **LOS_ListTailInsertList**: inserts the end of a DLL to the head of this DLL.|
| Deleting a node | - **LOS_ListDelete**: deletes a node from this DLL.<br>- **LOS_ListDelInit**: deletes a node from this DLL and uses this node to initialize the DLL.|
| Checking a DLL | - **LOS_ListEmpty**: checks whether a DLL is empty.<br>- **LOS_DL_LIST_IS_END**: checks whether a node is the tail of the DLL.<br>- **LOS_DL_LIST_IS_ON_QUEUE**: checks whether a node is in the DLL.|
| Obtaining structure information | - **LOS_OFF_SET_OF**: obtains the offset of a member in the specified structure relative to the start address of the structure.<br>- **LOS_DL_LIST_ENTRY**: obtains the address of the structure that contains the first node in the DLL. The first input parameter of the API indicates the head node in the list, the second input parameter indicates the name of the structure to be obtained, and the third input parameter indicates the name of the linked list in the structure.<br>- **LOS_ListPeekHeadType**: obtains the address of the structure that contains the first node in the linked list. The first input parameter of the API indicates the head node in the list, the second input parameter indicates the name of the structure to be obtained, and the third input parameter indicates the name of the linked list in the structure. Null will be returned if the DLL is empty.<br>- **LOS_ListRemoveHeadType**: obtains the address of the structure that contains the first node in the linked list, and deletes the first node from the list. The first input parameter of the API indicates the head node in the list, the second input parameter indicates the name of the structure to be obtained, and the third input parameter indicates the name of the linked list in the structure. Null will be returned if the DLL is empty.<br>- **LOS_ListNextType**: obtains the address of the structure that contains the next node of the specified node in the linked list. The first input parameter of the API indicates the head node in the list, the second input parameter indicates the specified node, the third parameter indicates the name of the structure to be obtained, and the fourth input parameter indicates the name of the linked list in the structure. If the next node of the linked list node is the head node and is empty, NULL will be returned.|
| Traversing a DLL | - **LOS_DL_LIST_FOR_EACH**: traverses a DLL.<br>- **LOS_DL_LIST_FOR_EACH_SAFE**: traverses the DLL and stores the subsequent nodes of the current node for security verification.|
| Traversing the structure that contains a DLL| - **LOS_DL_LIST_FOR_EACH_ENTRY**: traverses a DLL and obtains the address of the structure that contains the linked list node.<br>- **LOS_DL_LIST_FOR_EACH_ENTRY_SAFE**: traverses a DLL, obtains the address of the structure that contains the linked list node, and stores the address of the structure that contains the subsequent node of the current node.|
## How to Develop
......@@ -30,7 +29,7 @@ The typical development process of the DLL is as follows:
2. Call **LOS_ListAdd** to add a node into the DLL.
3. Call **LOS_ListTailInsert** to insert a node to the tail of the DLL.
3. Call **LOS_ListTailInsert** to insert a node into the tail of the DLL.
4. Call **LOS_ListDelete** to delete the specified node.
......@@ -39,18 +38,19 @@ The typical development process of the DLL is as follows:
6. Call **LOS_ListDelInit** to delete the specified node and initialize the DLL based on the node.
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**<br>
> - Pay attention to the operations operations of the front and back pointer of the node.
> **NOTE**<br>
>
> - Pay attention to the operations before and after the node pointer.
>
> - The DLL APIs are underlying interfaces and do not check whether the input parameters are empty. You must ensure that the input parameters are valid.
>
> - If the memory of a linked list node is dynamically allocated, release the memory when deleting the node.
**Development Example**
## Development Example
**Example Description**
### Example Description
This example implements the following:
......@@ -63,7 +63,11 @@ This example implements the following:
4. Check the operation result.
### Sample Code
The sample code can be compiled and verified in **./kernel/liteos_a/testsuites/kernel/src/osTest.c**. The **ListSample** function is called in **TestTaskEntry**.
The sample code is as follows:
```
#include "stdio.h"
......@@ -109,6 +113,8 @@ static UINT32 ListSample(VOID)
The development is successful if the return result is as follows:
```
Initial head
Add listNode1 success
......
# Standard Library
The OpenHarmony kernel uses the musl libc library that supports the Portable Operating System Interface \(POSIX\). You can develop components and applications working on the kernel based on the POSIX.
The OpenHarmony kernel uses the musl libc library that supports the Portable Operating System Interface (POSIX). You can develop components and applications working on the kernel based on the POSIX.
## Standard Library API Framework
**Figure 1** POSIX framework<a name="fig153258541429"></a>
**Figure 1** POSIX framework
![](figures/posix-framework.png "posix-framework")
The musl libc library supports POSIX standards. The OpenHarmony kernel adapts the related system call APIs to implement external functions.
For details about the APIs supported by the standard library, see the API document of the C library, which also covers the differences between the standard library and the POSIX standard library.
## Development Example
In this example, the main thread creates **THREAD\_NUM** child threads. Once a child thread is started, it enters the standby state. After the main thread successfully wakes up all child threads, they continue to execute until the lifecycle ends. The main thread uses the **pthread\_join** method to wait until all child threads are executed.
### Development Example
#### Example Description
In this example, the main thread creates THREAD_NUM child threads. Once a child thread is started, it enters the standby state. After the main thread successfully wakes up all child threads, they continue to execute until the lifecycle ends. The main thread uses the **pthread_join** method to wait until all child threads are executed.
#### Sample Code
The sample code can be compiled and verified in **./kernel/liteos_a/testsuites/kernel/src/osTest.c**. The **ExamplePosix** function is called in **TestTaskEntry**.
The sample code is as follows:
```
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
#define THREAD_NUM 3
int g_startNum = 0; /* Number of started threads */
int g_wakenNum = 0; /* Number of wakeup threads */
int g_startNum = 0; /* Number of threads to start */
int g_wakenNum = 0; /* Number of threads to wake up */
struct testdata {
pthread_mutex_t mutex;
pthread_cond_t cond;
} g_td;
/*
* Entry function of child threads.
*/
static void *ChildThreadFunc(void *arg)
/* Entry function of the child thread */
static VOID *ChildThreadFunc(VOID *arg)
{
int rc;
pthread_t self = pthread_self();
......@@ -47,7 +51,7 @@ static void *ChildThreadFunc(void *arg)
/* Acquire a mutex. */
rc = pthread_mutex_lock(&g_td.mutex);
if (rc != 0) {
printf("ERROR:take mutex lock failed, error code is %d!\n", rc);
dprintf("ERROR:take mutex lock failed, error code is %d!\n", rc);
goto EXIT;
}
......@@ -57,7 +61,7 @@ static void *ChildThreadFunc(void *arg)
/* Wait for the cond variable. */
rc = pthread_cond_wait(&g_td.cond, &g_td.mutex);
if (rc != 0) {
printf("ERROR: pthread condition wait failed, error code is %d!\n", rc);
dprintf("ERROR: pthread condition wait failed, error code is %d!\n", rc);
(void)pthread_mutex_unlock(&g_td.mutex);
goto EXIT;
}
......@@ -65,52 +69,53 @@ static void *ChildThreadFunc(void *arg)
/* Attempt to acquire a mutex, which is failed in normal cases. */
rc = pthread_mutex_trylock(&g_td.mutex);
if (rc == 0) {
printf("ERROR: mutex gets an abnormal lock!\n");
dprintf("ERROR: mutex gets an abnormal lock!\n");
goto EXIT;
}
/* The value of g_wakenNum is increased by 1. The value indicates the number of child threads that have been woken up by the cond variable. */
g_wakenNum++;
/* Unlock a mutex. */
/* Release a mutex. */
rc = pthread_mutex_unlock(&g_td.mutex);
if (rc != 0) {
printf("ERROR: mutex release failed, error code is %d!\n", rc);
dprintf("ERROR: mutex release failed, error code is %d!\n", rc);
goto EXIT;
}
EXIT:
return NULL;
}
static int testcase(void)
static int ExamplePosix(VOID)
{
int i, rc;
pthread_t thread[THREAD_NUM];
/* Initialize a mutex. */
/* Initialize the mutex. */
rc = pthread_mutex_init(&g_td.mutex, NULL);
if (rc != 0) {
printf("ERROR: mutex init failed, error code is %d!\n", rc);
dprintf("ERROR: mutex init failed, error code is %d!\n", rc);
goto ERROROUT;
}
/* Initialize the cond variable. */
rc = pthread_cond_init(&g_td.cond, NULL);
if (rc != 0) {
printf("ERROR: pthread condition init failed, error code is %d!\n", rc);
dprintf("ERROR: pthread condition init failed, error code is %d!\n", rc);
goto ERROROUT;
}
/* Create child threads in batches. The number is specified by THREAD_NUM. */
/* Create child threads in batches. */
for (i = 0; i < THREAD_NUM; i++) {
rc = pthread_create(&thread[i], NULL, ChildThreadFunc, NULL);
if (rc != 0) {
printf("ERROR: pthread create failed, error code is %d!\n", rc);
dprintf("ERROR: pthread create failed, error code is %d!\n", rc);
goto ERROROUT;
}
}
dprintf("pthread_create ok\n");
/* Wait until all child threads lock a mutex. */
/* Wait until all child threads obtain a mutex. */
while (g_startNum < THREAD_NUM) {
usleep(100);
}
......@@ -118,14 +123,14 @@ static int testcase(void)
/* Acquire a mutex and block all threads using pthread_cond_wait. */
rc = pthread_mutex_lock(&g_td.mutex);
if (rc != 0) {
printf("ERROR: mutex lock failed, error code is %d\n", rc);
dprintf("ERROR: mutex lock failed, error code is %d\n", rc);
goto ERROROUT;
}
/* Release a mutex. */
/* Release the mutex. */
rc = pthread_mutex_unlock(&g_td.mutex);
if (rc != 0) {
printf("ERROR: mutex unlock failed, error code is %d!\n", rc);
dprintf("ERROR: mutex unlock failed, error code is %d!\n", rc);
goto ERROROUT;
}
......@@ -133,7 +138,7 @@ static int testcase(void)
/* Broadcast signals on the cond variable. */
rc = pthread_cond_signal(&g_td.cond);
if (rc != 0) {
printf("ERROR: pthread condition failed, error code is %d!\n", rc);
dprintf("ERROR: pthread condition failed, error code is %d!\n", rc);
goto ERROROUT;
}
}
......@@ -142,73 +147,69 @@ static int testcase(void)
/* Check whether all child threads are woken up. */
if (g_wakenNum != THREAD_NUM) {
printf("ERROR: not all threads awaken, only %d thread(s) awaken!\n", g_wakenNum);
dprintf("ERROR: not all threads awaken, only %d thread(s) awaken!\n", g_wakenNum);
goto ERROROUT;
}
dprintf("all threads awaked\n");
/* Wait for all threads to terminate. */
/* Join all child threads, that is, wait for the end of all child threads. */
for (i = 0; i < THREAD_NUM; i++) {
rc = pthread_join(thread[i], NULL);
if (rc != 0) {
printf("ERROR: pthread join failed, error code is %d!\n", rc);
dprintf("ERROR: pthread join failed, error code is %d!\n", rc);
goto ERROROUT;
}
}
dprintf("all threads join ok\n");
/* Destroy the cond variable. */
rc = pthread_cond_destroy(&g_td.cond);
if (rc != 0) {
printf("ERROR: pthread condition destroy failed, error code is %d!\n", rc);
dprintf("ERROR: pthread condition destroy failed, error code is %d!\n", rc);
goto ERROROUT;
}
return 0;
ERROROUT:
return -1;
}
```
/*
* Main function
*/
int main(int argc, char *argv[])
{
int rc;
#### Verification
/* Start the test function. */
rc = testcase();
if (rc != 0) {
printf("ERROR: testcase failed!\n");
}
The output is as follows:
return 0;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif /* __cplusplus */
#endif /* __cplusplus */
```
pthread_create ok
all threads awaked
all threads join ok
```
## Differences from the Linux Standard Library
This section describes the key differences between the standard library carried by the OpenHarmony kernel and the Linux standard library. For more differences, see the API document of the C library.
The following describes the key differences between the standard library supported by the OpenHarmony kernel and the Linux standard library. For more differences, see the API document of the C library.
### Process
1. The OpenHarmony user-mode processes support only static priorities, which range from 10 \(highest\) to 31 \(lowest\).
2. The OpenHarmony user-mode threads support only static priorities, which range from 0 \(highest\) to 31 \(lowest\).
3. The OpenHarmony process scheduling supports **SCHED\_RR** only, and thread scheduling supports **SCHED\_RR** or **SCHED\_FIFO**.
- The OpenHarmony user-mode processes support only static priorities, which range from 10 (highest) to 31 (lowest).
- The OpenHarmony user-mode threads support only static priorities, which range from 0 (highest) to 31 (lowest).
- The OpenHarmony process scheduling supports **SCHED_RR** only, and thread scheduling supports **SCHED_RR** or **SCHED_FIFO**.
### Memory
**h2****Difference with Linux mmap**
**Differences from Linux mmap**
mmap prototype: **void \*mmap \(void \*addr, size\_t length, int prot, int flags, int fd, off\_t offset\)**
mmap prototype: **void \*mmap (void \*addr, size_t length, int prot, int flags, int fd, off_t offset)**
The lifecycle implementation of **fd** is different from that of Linux glibc. glibc releases the **fd** handle immediately after successfully invoking **mmap** for mapping. In the OpenHarmony kernel, you are not allowed to close the **fd** immediately after the mapping is successful. You can close the **fd** only after **munmap** is called. If you do not close **fd**, the OS reclaims the **fd** when the process exits.
**h2****Sample Code**
**Example**
Linux OS:
Linux:
```
int main(int argc, char *argv[])
......@@ -226,13 +227,14 @@ int main(int argc, char *argv[])
perror("mmap");
exit(EXIT_FAILURE);
}
close(fd); /* OpenHarmony does not support close fd immediately after the mapping is successful. */
close(fd); /* OpenHarmony does not support closing fd immediately after the mapping is successful. */
...
exit(EXIT_SUCCESS);
}
```
OpenHarmony:
OpenHarmony:
```
int main(int argc, char *argv[])
......@@ -257,22 +259,27 @@ int main(int argc, char *argv[])
}
```
### File System
**System directories**: You cannot modify system directories and device mount directories, which include **/dev**, **/proc**, **/app**, **/bin**, **/data**, **/etc**, **/lib**, **/system** and **/usr**.
System directories: You cannot modify system directories and device mount directories, which include **/dev**, **/proc**, **/app**, **/bin**, **/data**, **/etc**, **/lib**, **/system**, and **/usr**.
**User directory**: The user directory refers to the **/storage** directory. You can create, read, and write files in this directory, but cannot mount devices.
User directory: The user directory refers to the **/storage** directory. You can create, read, and write files in this directory, but cannot mount it to a device.
Except in the system and user directories, you can create directories and mount them to devices. Note that nested mount is not allowed, that is, a mounted folder and its subfolders cannot be mounted repeatedly. A non-empty folder cannot be mounted.
Except in the system and user directories, you can create directories and mount devices. Note that nested mount is not allowed, that is, a mounted folder and its subfolders cannot be mounted repeatedly. A non-empty folder cannot be mounted.
### Signal
- The default behavior for signals does not include **STOP**, **CONTINUE**, or **COREDUMP**.
- A sleeping process \(for example, a process enters the sleeping status by calling the sleep function\) cannot be woken up by a signal. The signal mechanism does not support the wakeup function. The behavior for a signal can be processed only when the process is scheduled by the CPU.
- A sleeping process (for example, a process enters the sleeping status by calling the sleep function) cannot be woken up by a signal. The signal mechanism does not support the wakeup function. The behavior for a signal can be processed only when the process is scheduled by the CPU.
- After a process exits, **SIGCHLD** is sent to the parent process. The sending action cannot be canceled.
- Only signals 1 to 30 are supported. The callback is executed only once even if the same signal is received multiple times.
### Time
- Only signals 1 to 30 are supported. The callback is invoked only once even if the same signal is received multiple times.
The OpenHarmony time precision is based on tick. The default value is 10 ms/tick. The time error of the **sleep** and **timeout** functions is less than or equal to 20 ms.
### Time
The default time precision of OpenHarmony is 10 ms/tick. The time error of the **sleep** and **timeout** functions is less than or equal to 20 ms.
# Event
## Basic Concepts<a name="section122115620816"></a>
An event is a mechanism for communication between tasks. It can be used to synchronize tasks.
## Basic Concepts
An event is a communication mechanism used to synchronize tasks.
In multi-task environment, synchronization is required between tasks. Events can be used for synchronization in the following cases:
- One-to-many synchronization: A task waits for the triggering of multiple events. A task is woken up by one or multiple events.
- One-to-many synchronization: A task waits for the triggering of multiple events. A task can be woken up by one or multiple events.
- Many-to-many synchronization: Multiple tasks wait for the triggering of multiple events.
The event mechanism provided by the OpenHarmony LiteOS-A event module has the following features:
- A task triggers or waits for an event by creating an event control block.
- Events are independent of each other. The internal implementation is a 32-bit unsigned integer, and each bit indicates an event type. The 25th bit is unavailable. Therefore, a maximum of 31 event types are supported.
- Events are used only for synchronization between tasks, but not for data transmission.
- Writing the same event type to the event control block for multiple times is equivalent to writing the event type only once before the event control block is cleared.
- Events are independent of each other. The internal implementation is a 32-bit unsigned integer, and each bit indicates an event type. The value **0** indicates that the event type does not occur, and the value **1** indicates that the event type has occurred. There are 31 event types in total. The 25th bit (`0x02U << 24`) is reserved.
- Events are used for task synchronization, but not for data transmission.
- Writing the same event type to an event control block multiple times is equivalent to writing the event type only once before the event control block is cleared.
- Multiple tasks can read and write the same event.
- The event read/write timeout mechanism is supported.
## Working Principles<a name="section94611116593"></a>
### Event Control Block<a name="section1161415384467"></a>
## Working Principles
### Event Control Block
```
/**
* Event control block data structure
* Event control block data structure
*/
typedef struct tagEvent {
UINT32 uwEventID; /* Event set, which is a collection of events processed (written and cleared). */
LOS_DL_LIST stEventList; /* List of tasks waiting for specific events */
LOS_DL_LIST stEventList; /* List of tasks waiting for specific events. */
} EVENT_CB_S, *PEVENT_CB_S;
```
### Working Principles<a name="section187761153144617"></a>
**Initializing an event**: An event control block is created to maintain a collection of processed events and a linked list of tasks waiting for specific events.
### Working Principles
**Initializing an Event**
An event control block is created to maintain a set of processed events and a linked list of tasks waiting for specific events.
**Writing an event**: When a specified event is written to the event control block, the event control block updates the event set, traverses the task linked list, and determines whether to wake up related task based on the task conditions.
**Writing an Event**
**Reading an event**: If the read event already exists, it is returned synchronously. In other cases, the return time is determined based on the timeout period and event triggering status. If the wait event condition is met before the timeout period expires, the blocked task will be directly woken up. Otherwise, the blocked task will be woken up only after the timeout period has expired.
When an event is written to the event control block, the event control block updates the event set, traverses the task linked list, and determines whether to wake up related task based on the specified conditions.
The input parameters **eventMask** and **mode** determine whether the condition for reading an event is met. **eventMask** indicates the mask of the event. **mode** indicates the handling mode, which can be any of the following:
**Reading an Event**
- **LOS\_WAITMODE\_AND**: Event reading is successful only when all the events corresponding to **eventMask** occur. Otherwise, the task will be blocked, or an error code will be returned.
- **LOS\_WAITMODE\_OR**: Event reading is successful when any of the events corresponding to **eventMask** occurs. Otherwise, the task will be blocked, or an error code will be returned.
- **LOS\_WAITMODE\_CLR**: This mode must be used with **LOS\_WAITMODE\_AND** or **LOS\_WAITMODE\_OR** \(LOS\_WAITMODE\_AND | LOS\_WAITMODE\_CLR or LOS\_WAITMODE\_OR | LOS\_WAITMODE\_CLR\). In this mode, if **LOS\_WAITMODE\_AND** or **LOS\_WAITMODE\_OR** is successful, the corresponding event type bit in the event control block will be automatically cleared.
If the event to read already exists, it is returned synchronously. In other cases, the event is returned based on the timeout period and event triggering conditions. If the wait condition is met before the timeout period expires, the blocked task will be directly woken up. Otherwise, the blocked task will be woken up only after the timeout period has expired.
**Clearing events**: Clear the event set of the event control block based on the specified mask. If the mask is **0**, the event set will be cleared. If the mask is **0xffff**, no event will be cleared, and the event set remains unchanged.
The parameters **eventMask** and **mode** determine whether the condition for reading an event is met. **eventMask** specifies the event mask. **mode** specifies the handling mode, which can be any of the following:
**Destroying an event**: Destroy the specified event control block.
- **LOS_WAITMODE_AND**: Read the event only when all the events corresponding to **eventMask** occur. Otherwise, the task will be blocked, or an error code will be returned.
**Figure 1** Event working mechanism for small systems<a name="fig17799175324612"></a>
![](figures/event-working-mechanism-for-small-systems.png "event-working-mechanism-for-small-systems")
- **LOS_WAITMODE_OR**: Read the event only when any of the events corresponding to **eventMask** occur. Otherwise, the task will be blocked, or an error code will be returned.
## Development Guidelines<a name="section44744471891"></a>
- **LOS_WAITMODE_CLR**: This mode must be used with one or all of the event modes (LOS_WAITMODE_AND | LOS_WAITMODE_CLR or LOS_WAITMODE_OR | LOS_WAITMODE_CLR). In this mode, if all event modes or any event mode is successful, the corresponding event type bit in the event control block will be automatically cleared.
### Available APIs<a name="section172373513919"></a>
**Clearing Events**
The events in the event set of the event control block can be cleared based on the specified mask. The mask **0** means to clear the event set; the mask **0xffff** means the opposite.
**Destroying Events**
The event control block can be destroyed to release resources.
**Figure 1** Event working mechanism for small systems
![](figures/event-working-mechanism-for-small-systems.png "event-working-mechanism-for-small-systems")
## Development Guidelines
### Available APIs
The following table describes APIs available for the OpenHarmony LiteOS-A event module.
**Table 1** Event module APIs
<a name="table1415203765610"></a>
<table><thead align="left"><tr id="row134151837125611"><th class="cellrowborder" valign="top" width="12.85128512851285%" id="mcps1.2.4.1.1"><p id="p16415637105612"><a name="p16415637105612"></a><a name="p16415637105612"></a>Function</p>
</th>
<th class="cellrowborder" valign="top" width="29.8029802980298%" id="mcps1.2.4.1.2"><p id="p11415163718562"><a name="p11415163718562"></a><a name="p11415163718562"></a>API</p>
</th>
<th class="cellrowborder" valign="top" width="57.34573457345735%" id="mcps1.2.4.1.3"><p id="p1641533755612"><a name="p1641533755612"></a><a name="p1641533755612"></a>Description</p>
</th>
</tr>
</thead>
<tbody><tr id="row0415737175610"><td class="cellrowborder" valign="top" width="12.85128512851285%" headers="mcps1.2.4.1.1 "><p id="p9598124913544"><a name="p9598124913544"></a><a name="p9598124913544"></a>Initializing events</p>
</td>
<td class="cellrowborder" valign="top" width="29.8029802980298%" headers="mcps1.2.4.1.2 "><p id="p77891354175812"><a name="p77891354175812"></a><a name="p77891354175812"></a>LOS_EventInit</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p2334141425515"><a name="p2334141425515"></a><a name="p2334141425515"></a>Initializes an event control block.</p>
</td>
</tr>
<tr id="row421753455514"><td class="cellrowborder" rowspan="2" valign="top" width="12.85128512851285%" headers="mcps1.2.4.1.1 "><p id="p13441112105813"><a name="p13441112105813"></a><a name="p13441112105813"></a>Reading/Writing events</p>
</td>
<td class="cellrowborder" valign="top" width="29.8029802980298%" headers="mcps1.2.4.1.2 "><p id="p17234205011559"><a name="p17234205011559"></a><a name="p17234205011559"></a>LOS_EventRead</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p1621275475517"><a name="p1621275475517"></a><a name="p1621275475517"></a>Reads a specified type of event, with the timeout period of a relative time period in ticks.</p>
</td>
</tr>
<tr id="row13129193718555"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p17477615564"><a name="p17477615564"></a><a name="p17477615564"></a>LOS_EventWrite</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p10271958567"><a name="p10271958567"></a><a name="p10271958567"></a>Writes a specified type of event.</p>
</td>
</tr>
<tr id="row1831124035511"><td class="cellrowborder" valign="top" width="12.85128512851285%" headers="mcps1.2.4.1.1 "><p id="p1313401559"><a name="p1313401559"></a><a name="p1313401559"></a>Clearing events</p>
</td>
<td class="cellrowborder" valign="top" width="29.8029802980298%" headers="mcps1.2.4.1.2 "><p id="p7788152419567"><a name="p7788152419567"></a><a name="p7788152419567"></a>LOS_EventClear</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p14862153525620"><a name="p14862153525620"></a><a name="p14862153525620"></a>Clears a specified type of event.</p>
</td>
</tr>
<tr id="row1525316428553"><td class="cellrowborder" valign="top" width="12.85128512851285%" headers="mcps1.2.4.1.1 "><p id="p4253144265519"><a name="p4253144265519"></a><a name="p4253144265519"></a>Checking the event mask</p>
</td>
<td class="cellrowborder" valign="top" width="29.8029802980298%" headers="mcps1.2.4.1.2 "><p id="p768611115563"><a name="p768611115563"></a><a name="p768611115563"></a>LOS_EventPoll</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p13998115465617"><a name="p13998115465617"></a><a name="p13998115465617"></a>Returns whether the event input by the user meets the expectation based on the event ID, event mask, and read mode passed by the user.</p>
</td>
</tr>
<tr id="row6447135825614"><td class="cellrowborder" valign="top" width="12.85128512851285%" headers="mcps1.2.4.1.1 "><p id="p104471658155615"><a name="p104471658155615"></a><a name="p104471658155615"></a>Destroying events</p>
</td>
<td class="cellrowborder" valign="top" width="29.8029802980298%" headers="mcps1.2.4.1.2 "><p id="p15259169573"><a name="p15259169573"></a><a name="p15259169573"></a>LOS_EventDestroy</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p32592615573"><a name="p32592615573"></a><a name="p32592615573"></a>Destroys a specified event control block.</p>
</td>
</tr>
</tbody>
</table>
### How to Develop<a name="section1118215161013"></a>
**Table 1** APIs of the event module
| Category| API Description |
| -------- | -------- |
| Initializing an event| **LOS_EventInit**: initializes an event control block.|
| Reading/Writing an event| - **LOS_EventRead**: reads an event, with a relative timeout period in ticks.<br>- **LOS_EventWrite**: writes an event. |
| Clearing events| **LOS_EventClear**: clears a specified type of events.|
| Checking the event mask| **LOS_EventPoll**: checks whether the specified event occurs.|
| Destroying events | **LOS_EventDestroy**: destroys an event control block.|
### How to Develop
The typical event development process is as follows:
1. Initialize an event control block.
2. Block a read event control block.
2. Block a read event.
3. Write related events.
4. Wake up a blocked task, read the event, and check whether the event meets conditions.
5. Handle the event control block.
6. Destroy an event control block.
>![](../public_sys-resources/icon-note.gif) **NOTE:**
>- When an event is read or written, the 25th bit of the event is reserved and cannot be set.
>- Repeated writes of the same event are treated as one write.
> **NOTE**
>
> - For event read and write operations, the 25th bit (`0x02U << 24`) of the event is reserved and cannot be set.
>
> - Repeated writes of the same event are treated as one write.
## Development Example
### Example Description
In this example, run the **Example_TaskEntry** task to create the **Example_Event** task. Run the **Example_Event** task to read an event to trigger task switching. Run the **Example_TaskEntry** task to write an event. You can understand the task switching during event operations based on the sequence in which logs are recorded.
## Development Example<a name="section5837165132911"></a>
1. Create the **Example_Event** task in the **Example_TaskEntry** task with a higher priority than the **Example_TaskEntry** task.
### Example Description<a name="section128221510145718"></a>
2. Run the **Example_Event** task to read event **0x00000001**. Task switching is triggered to execute the **Example_TaskEntry** task.
In this example, run the **Example\_TaskEntry** task to create the **Example\_Event** task, run the **Example\_Event** task to read an event to trigger task switching, and run the **Example\_TaskEntry** task to write an event. You can understand the task switching during event operations based on the sequence in which logs are recorded.
3. Run the **Example_TaskEntry** task to write event **0x00000001**. Task switching is triggered to execute the **Example_Event** task.
1. Create the **Example\_Event** task in the **Example\_TaskEntry** task with a higher priority than the **Example\_TaskEntry** task.
2. Run the **Example\_Event** task to read event **0x00000001**. Task switching is triggered to execute the **Example\_TaskEntry** task.
3. Run the **Example\_TaskEntry** task to write event **0x00000001**. Task switching is triggered to execute the **Example\_Event** task.
4. The **Example\_Event** task is executed.
5. The **Example\_TaskEntry** task is executed.
4. The **Example_Event** task is executed.
### Sample Code<a name="section71507479577"></a>
5. The **Example_TaskEntry** task is executed.
### Sample Code
The sample code can be compiled and verified in **./kernel/liteos_a/testsuites/kernel/src/osTest.c**. The **Example_EventEntry** function is called in **TestTaskEntry**.
The sample code is as follows:
......@@ -149,28 +148,28 @@ The sample code is as follows:
#include "los_task.h"
#include "securec.h"
/* Task ID*/
/* Task ID */
UINT32 g_testTaskId;
/* Event control structure*/
/* Event control structure */
EVENT_CB_S g_exampleEvent;
/* Type of the wait event*/
/* Type of the wait event */
#define EVENT_WAIT 0x00000001
/* Example task entry function*/
#define EVENT_TIMEOUT 500
/* Example task entry function */
VOID Example_Event(VOID)
{
UINT32 event;
/* Set a timeout period for event reading to 100 ticks. If the specified event is not read within 100 ticks, the read operation times out and the task is woken up.*/
printf("Example_Event wait event 0x%x \n", EVENT_WAIT);
/* Set a timeout period for event reading to 100 ticks. If the specified event is not read within 100 ticks, the read operation times out and the task is woken up. */
dprintf("Example_Event wait event 0x%x \n", EVENT_WAIT);
event = LOS_EventRead(&g_exampleEvent, EVENT_WAIT, LOS_WAITMODE_AND, 100);
event = LOS_EventRead(&g_exampleEvent, EVENT_WAIT, LOS_WAITMODE_AND, EVENT_TIMEOUT);
if (event == EVENT_WAIT) {
printf("Example_Event,read event :0x%x\n", event);
dprintf("Example_Event,read event :0x%x\n", event);
} else {
printf("Example_Event,read event timeout\n");
dprintf("Example_Event,read event timeout\n");
}
}
......@@ -179,14 +178,14 @@ UINT32 Example_EventEntry(VOID)
UINT32 ret;
TSK_INIT_PARAM_S task1;
/* Initialize the event.*/
/* Initialize the event. */
ret = LOS_EventInit(&g_exampleEvent);
if (ret != LOS_OK) {
printf("init event failed .\n");
dprintf("init event failed .\n");
return -1;
}
/* Create a task.*/
/* Create a task. */
(VOID)memset_s(&task1, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
task1.pfnTaskEntry = (TSK_ENTRY_FUNC)Example_Event;
task1.pcName = "EventTsk1";
......@@ -194,39 +193,34 @@ UINT32 Example_EventEntry(VOID)
task1.usTaskPrio = 5;
ret = LOS_TaskCreate(&g_testTaskId, &task1);
if (ret != LOS_OK) {
printf("task create failed.\n");
dprintf("task create failed.\n");
return LOS_NOK;
}
/* Write the task wait event (g_testTaskId). */
printf("Example_TaskEntry write event.\n");
dprintf("Example_TaskEntry write event.\n");
ret = LOS_EventWrite(&g_exampleEvent, EVENT_WAIT);
if (ret != LOS_OK) {
printf("event write failed.\n");
dprintf("event write failed.\n");
return LOS_NOK;
}
/* Clear the flag.*/
printf("EventMask:%d\n", g_exampleEvent.uwEventID);
/* Clear the flag. */
dprintf("EventMask:%d\n", g_exampleEvent.uwEventID);
LOS_EventClear(&g_exampleEvent, ~g_exampleEvent.uwEventID);
printf("EventMask:%d\n", g_exampleEvent.uwEventID);
/* Delete the task.*/
ret = LOS_TaskDelete(g_testTaskId);
if (ret != LOS_OK) {
printf("task delete failed.\n");
return LOS_NOK;
}
dprintf("EventMask:%d\n", g_exampleEvent.uwEventID);
return LOS_OK;
}
```
### Verification<a name="section16570171645813"></a>
### Verification
The development is successful if the return result is as follows:
```
Example_Event wait event 0x1
Example_TaskEntry write event.
......@@ -234,4 +228,3 @@ Example_Event,read event :0x1
EventMask:1
EventMask:0
```
# Semaphore
## Basic Concepts<a name="section1577111168131"></a>
## Basic Concepts
Semaphore is a mechanism for implementing inter-task communication. It implements synchronization between tasks or exclusive access to shared resources.
Semaphore is a mechanism used to implement synchronization between tasks or exclusive access to shared resources.
In the data structure of a semaphore, there is a value indicating the number of shared resources available. The value can be:
In the semaphore data structure, there is a value indicating the number of shared resources available. The value can be:
- **0**: The semaphore is unavailable. In this case, tasks waiting for the semaphore may exist.
- **0**: The semaphore is unavailable. Tasks waiting for the semaphore may exist.
- Positive number: The semaphore is available.
The semaphore for exclusive access is different from the semaphore for synchronization:
The semaphore used for exclusive access to resources is different from the semaphore used for synchronization:
- Semaphore used for exclusive access: The initial semaphore counter value \(non-zero\) indicates the number of shared resources available. A semaphore must be acquired before a shared resource is used, and released when the resource is no longer required. When all shared resources are used, the semaphore counter is reduced to 0 and all tasks requiring the semaphore will be blocked. This ensures exclusive access to shared resources. In addition, if the number of shared resources is 1, a binary semaphore \(similar to the mutex mechanism\) is recommended.
- Semaphore used for synchronization: The initial semaphore counter value is **0**. A task without the semaphore will be blocked, and enters the Ready or Running state only when the semaphore is released by another task or an interrupt.
- Semaphore used for exclusive access: The initial semaphore counter value \(non-zero\) indicates the number of shared resources available. The semaphore counter value must be acquired before a shared resource is used, and released when the resource is no longer required. When all shared resources are used, the semaphore counter is reduced to 0 and the tasks that need to obtain the semaphores will be blocked. This ensures exclusive access to shared resources. In addition, when the number of shared resources is 1, a binary semaphore \(similar to the mutex mechanism\) is recommended.
- Semaphore used for synchronization: The initial semaphore counter value is **0**. Task 1 cannot acquire the semaphore and is blocked. Task 1 enters Ready or Running state only when the semaphore is released by task 2 or an interrupt. In this way, task synchronization is implemented.
## Working Principles<a name="section118423019134"></a>
## Working Principles
**Semaphore Control Block**
```
/**
* Data structure of the semaphore control block
*/
typedef struct {
UINT16 semStat; /* Semaphore status */
UINT16 semType; /* Semaphore type*/
UINT16 semCount; /* Semaphore count*/
UINT16 semId; /* Semaphore index*/
LOS_DL_LIST semList; /* Mount the task blocked by the semaphore.*/
UINT16 semType; /* Semaphore type */
UINT16 semCount; /* Semaphore count */
UINT16 semId; /* Semaphore ID */
LOS_DL_LIST semList; /* List of blocked tasks */
} LosSemCB;
```
......@@ -38,100 +42,87 @@ Semaphore allows only a specified number of tasks to access a shared resource at
- Semaphore initialization
The system allocates memory for the semaphores configured \(you can configure the number of semaphores using the **LOSCFG\_BASE\_IPC\_SEM\_LIMIT** macro\), initializes all semaphores to be unused semaphores, and adds them to a linked list for the system to use.
Allocate memory for the semaphores (the number of semaphores is specified by the **LOSCFG_BASE_IPC_SEM_LIMIT** macro), set all semaphores to the unused state, and add them to a linked list.
- Semaphore creation
The system obtains a semaphore from the linked list of unused semaphores and assigns an initial value to the semaphore.
Obtain a semaphore from the linked list of unused semaphores and assign an initial value to the semaphore.
- Semaphore request
If the counter value is greater than 0, the system allocates a semaphore, decreases the value by 1, and returns a success message. Otherwise, the system blocks the task and moves the task to the end of a task queue waiting for semaphores. The wait timeout period can be set.
If the counter value is greater than 0 when a semaphore is requsted, the counter is decreased by 1 and a success message is returned. Otherwise, the task is blocked and added to the end of a task queue waiting for semaphores. The wait timeout period can be set.
- Semaphore release
When a semaphore is released, if there is no task waiting for it, the counter value is increased by 1. Otherwise, the first task in the wait queue is woken up.
If no task is waiting for the semaphore, the counter is incremented by 1. Otherwise, wake up the first task in the wait queue.
- Semaphore deletion
The system sets a semaphore in use to unused state and inserts it to the linked list of unused semaphores.
Set a semaphore in use to the unused state and add it to the linked list of unused semaphores.
The following figure illustrates the semaphore working mechanism.
**Figure 1** Semaphore working mechanism for small systems<a name="fig467314634214"></a>
**Figure 1** Semaphore working mechanism for the small system
![](figures/semaphore-working-mechanism-for-small-systems.png "semaphore-working-mechanism-for-small-systems")
## Development Guidelines<a name="section01419503131"></a>
### Available APIs<a name="section1232345431312"></a>
**Table 1** Semaphore module APIs
<a name="table1415203765610"></a>
<table><thead align="left"><tr id="row134151837125611"><th class="cellrowborder" valign="top" width="12.85128512851285%" id="mcps1.2.4.1.1"><p id="p16415637105612"><a name="p16415637105612"></a><a name="p16415637105612"></a>Function</p>
</th>
<th class="cellrowborder" valign="top" width="29.8029802980298%" id="mcps1.2.4.1.2"><p id="p11415163718562"><a name="p11415163718562"></a><a name="p11415163718562"></a>API</p>
</th>
<th class="cellrowborder" valign="top" width="57.34573457345735%" id="mcps1.2.4.1.3"><p id="p1641533755612"><a name="p1641533755612"></a><a name="p1641533755612"></a>Description</p>
</th>
</tr>
</thead>
<tbody><tr id="row0415737175610"><td class="cellrowborder" rowspan="3" valign="top" width="12.85128512851285%" headers="mcps1.2.4.1.1 "><p id="p8866127195914"><a name="p8866127195914"></a><a name="p8866127195914"></a>Creating or deleting a semaphore</p>
</td>
<td class="cellrowborder" valign="top" width="29.8029802980298%" headers="mcps1.2.4.1.2 "><p id="p58621910185914"><a name="p58621910185914"></a><a name="p58621910185914"></a>LOS_SemCreate</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p48623102592"><a name="p48623102592"></a><a name="p48623102592"></a>Creates a semaphore and returns the semaphore ID.</p>
</td>
</tr>
<tr id="row1213865218584"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p20862510115911"><a name="p20862510115911"></a><a name="p20862510115911"></a>LOS_BinarySemCreate</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1886211011599"><a name="p1886211011599"></a><a name="p1886211011599"></a>Creates a binary semaphore. The maximum counter value is <strong id="b4125169919"><a name="b4125169919"></a><a name="b4125169919"></a>1</strong>.</p>
</td>
</tr>
<tr id="row3231257145813"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p38621410205919"><a name="p38621410205919"></a><a name="p38621410205919"></a>LOS_SemDelete</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p586261085913"><a name="p586261085913"></a><a name="p586261085913"></a>Deletes a semaphore.</p>
</td>
</tr>
<tr id="row73651459105815"><td class="cellrowborder" rowspan="2" valign="top" width="12.85128512851285%" headers="mcps1.2.4.1.1 "><p id="p16927183515593"><a name="p16927183515593"></a><a name="p16927183515593"></a>Requesting or releasing a semaphore</p>
</td>
<td class="cellrowborder" valign="top" width="29.8029802980298%" headers="mcps1.2.4.1.2 "><p id="p955271555916"><a name="p955271555916"></a><a name="p955271555916"></a>LOS_SemPend</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p555221518598"><a name="p555221518598"></a><a name="p555221518598"></a>Requests a specified semaphore and sets the timeout period.</p>
</td>
</tr>
<tr id="row178321454145812"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p17552101519596"><a name="p17552101519596"></a><a name="p17552101519596"></a>LOS_SemPost</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1555261595915"><a name="p1555261595915"></a><a name="p1555261595915"></a>Posts (releases) a semaphore.</p>
</td>
</tr>
</tbody>
</table>
### How to Develop<a name="section154261711141419"></a>
1. Call **LOS\_SemCreate** to create a semaphore. To create a binary semaphore, call **LOS\_BinarySemCreate**.
2. Call **LOS\_SemPend** to request a semaphore.
3. Call **LOS\_SemPost** to release a semaphore.
4. Call **LOS\_SemDelete** to delete a semaphore.
>![](../public_sys-resources/icon-note.gif) **NOTE:**
>As interrupts cannot be blocked, semaphores cannot be requested in block mode for interrupts.
### Development Example<a name="section658135571417"></a>
### Example Description<a name="section125244411653"></a>
## Development Guidelines
### Available APIs
**Table 1** APIs for creating and deleting a semaphore
| API| Description|
| -------- | -------- |
| LOS_SemCreate | Creates a semaphore and returns the semaphore ID.|
| LOS_BinarySemCreate | Creates a binary semaphore. The maximum counter value is **1**.|
| LOS_SemDelete | Deletes a semaphore.|
**Table 2** APIs for requesting and releasing a semaphore
| API| Description|
| -------- | -------- |
| LOS_SemPend | Requests a semaphore and sets a timeout period.|
| LOS_SemPost | Releases a semaphore.|
### How to Develop
1. Call **LOS_SemCreate** to create a semaphore. To create a binary semaphore, call **LOS_BinarySemCreate**.
2. Call **LOS_SemPend** to request a semaphore.
3. Call **LOS_SemPost** to release a semaphore.
4. Call **LOS_SemDelete** to delete a semaphore.
> **NOTE**<br>
> As interrupts cannot be blocked, semaphores cannot be requested in block mode for interrupts.
### Development Example
### Example Description
This example implements the following:
1. Create a semaphore in task **ExampleSem** and lock task scheduling. Create two tasks **ExampleSemTask1** and **ExampleSemTask2** \(with higher priority\). Enable the two tasks to request the same semaphore. Unlock task scheduling. Enable task **ExampleSem** to enter sleep mode for 400 ticks. Release the semaphore in task **ExampleSem**.
2. Enable** ExampleSemTask2** to enter sleep mode for 20 ticks after acquiring the semaphore. \(When **ExampleSemTask2** is delayed, **ExampleSemTask1** is woken up.\)
3. Enable **ExampleSemTask1** to request the semaphore in scheduled block mode, with a wait timeout period of 10 ticks. \(Because the semaphore is still held by **ExampleSemTask2**, **ExampleSemTask1** is suspended. **ExampleSemTask1** is woken up after 10 ticks.\) Enable **ExampleSemTask1** to request the semaphore in permanent block mode after it is woken up 10 ticks later. \(Because the semaphore is still held by **ExampleSemTask2**, **ExampleSemTask1** is suspended.\)
1. Create a semaphore in task **ExampleSem** and lock task scheduling. Create two tasks **ExampleSemTask1** and **ExampleSemTask2** (with higher priority). Enable the two tasks to request the same semaphore. Unlock task scheduling. Enable task **ExampleSem** to enter sleep mode for 400 ticks. Release the semaphore in task **ExampleSem**.
2. Enable **ExampleSemTask2** to enter sleep mode for 20 ticks after acquiring the semaphore. (When **ExampleSemTask2** is delayed, **ExampleSemTask1** is woken up.)
3. Enable **ExampleSemTask1** to request the semaphore in scheduled block mode, with a wait timeout period of 10 ticks. (Because the semaphore is still held by **ExampleSemTask2**, **ExampleSemTask1** is suspended. **ExampleSemTask1** is woken up after 10 ticks.) Enable **ExampleSemTask1** to request the semaphore in permanent block mode after it is woken up 10 ticks later. (Because the semaphore is still held by **ExampleSemTask2**, **ExampleSemTask1** is suspended.)
4. After 20 ticks, **ExampleSemTask2** is woken up and releases the semaphore. **ExampleSemTask1** acquires the semaphore and is scheduled to run. When **ExampleSemTask1** is complete, it releases the semaphore.
5. Task **ExampleSem** is woken up after 400 ticks and deletes the semaphore.
### Sample Code<a name="section1742105514512"></a>
5. Task **ExampleSem** is woken up after 400 ticks. After that, delete the semaphore.
### Sample Code
The sample code can be compiled and verified in **./kernel/liteos_a/testsuites/kernel/src/osTest.c**. The **ExampleSem** function is called in **TestTaskEntry**.
The sample code is as follows:
......@@ -144,33 +135,34 @@ static UINT32 g_testTaskId01;
static UINT32 g_testTaskId02;
/* Task priority */
#define TASK_PRIO_TEST 5
#define TASK_PRIO_LOW 5
#define TASK_PRIO_HI 4
/* Semaphore structure ID*/
/* Semaphore structure ID */
static UINT32 g_semId;
VOID ExampleSemTask1(VOID)
{
UINT32 ret;
printf("ExampleSemTask1 try get sem g_semId, timeout 10 ticks.\n");
dprintf("ExampleSemTask1 try get sem g_semId, timeout 10 ticks.\n");
/* Request the semaphore in scheduled block mode, with a wait timeout period of 10 ticks.*/
/* Request the semaphore in scheduled block mode, with a wait timeout period of 10 ticks. */
ret = LOS_SemPend(g_semId, 10);
/* The semaphore is acquired.*/
/* The semaphore is acquired. */
if (ret == LOS_OK) {
LOS_SemPost(g_semId);
return;
}
/* The semaphore is not acquired when the timeout period has expired.*/
/* The semaphore is not acquired when the timeout period has expired. */
if (ret == LOS_ERRNO_SEM_TIMEOUT) {
printf("ExampleSemTask1 timeout and try get sem g_semId wait forever.\n");
dprintf("ExampleSemTask1 timeout and try get sem g_semId wait forever.\n");
/* Request the semaphore in permanent block mode.*/
/* Request the semaphore in permanent block mode. */
ret = LOS_SemPend(g_semId, LOS_WAIT_FOREVER);
printf("ExampleSemTask1 wait_forever and get sem g_semId.\n");
dprintf("ExampleSemTask1 wait_forever and get sem g_semId.\n");
if (ret == LOS_OK) {
dprintf("ExampleSemTask1 post sem g_semId.\n");
LOS_SemPost(g_semId);
return;
}
......@@ -180,20 +172,19 @@ VOID ExampleSemTask1(VOID)
VOID ExampleSemTask2(VOID)
{
UINT32 ret;
printf("ExampleSemTask2 try get sem g_semId wait forever.\n");
dprintf("ExampleSemTask2 try get sem g_semId wait forever.\n");
/* Request the semaphore in permanent block mode.*/
/* Request the semaphore in permanent block mode. */
ret = LOS_SemPend(g_semId, LOS_WAIT_FOREVER);
if (ret == LOS_OK) {
printf("ExampleSemTask2 get sem g_semId and then delay 20 ticks.\n");
dprintf("ExampleSemTask2 get sem g_semId and then delay 20 ticks.\n");
}
/* Enable the task to enter sleep mode for 20 ticks.*/
/* Enable the task to enter sleep mode for 20 ticks. */
LOS_TaskDelay(20);
printf("ExampleSemTask2 post sem g_semId.\n");
/* Release the semaphore.*/
dprintf("ExampleSemTask2 post sem g_semId.\n");
/* Release the semaphore. */
LOS_SemPost(g_semId);
return;
}
......@@ -204,42 +195,45 @@ UINT32 ExampleSem(VOID)
TSK_INIT_PARAM_S task1;
TSK_INIT_PARAM_S task2;
/* Create a semaphore.*/
/* Create a semaphore. */
LOS_SemCreate(0, &g_semId);
/* Lock task scheduling.*/
/* Lock task scheduling. */
LOS_TaskLock();
/* Create task 1.*/
/* Create task 1. */
(VOID)memset_s(&task1, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
task1.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleSemTask1;
task1.pcName = "TestTask1";
task1.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
task1.usTaskPrio = TASK_PRIO_TEST;
task1.usTaskPrio = TASK_PRIO_LOW;
ret = LOS_TaskCreate(&g_testTaskId01, &task1);
if (ret != LOS_OK) {
printf("task1 create failed .\n");
dprintf("task1 create failed .\n");
return LOS_NOK;
}
/* Create task 2.*/
/* Create task 2. */
(VOID)memset_s(&task2, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
task2.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleSemTask2;
task2.pcName = "TestTask2";
task2.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
task2.usTaskPrio = (TASK_PRIO_TEST - 1);
task2.usTaskPrio = TASK_PRIO_HI;
ret = LOS_TaskCreate(&g_testTaskId02, &task2);
if (ret != LOS_OK) {
printf("task2 create failed.\n");
dprintf("task2 create failed.\n");
return LOS_NOK;
}
/* Unlock task scheduling.*/
/* Unlock task scheduling. */
LOS_TaskUnlock();
/* Enable the task to enter sleep mode for 400 ticks. */
LOS_TaskDelay(400);
ret = LOS_SemPost(g_semId);
/* Enable the task to enter sleep mode for 400 ticks.*/
/* Enable the task to enter sleep mode for 400 ticks. */
LOS_TaskDelay(400);
/* Delete the semaphore. */
......@@ -248,16 +242,18 @@ UINT32 ExampleSem(VOID)
}
```
### Verification<a name="section11297301617"></a>
### Verification
The development is successful if the return result is as follows:
```
ExampleSemTask2 try get sem g_semId wait forever.
ExampleSemTask2 get sem g_semId and then delay 20 ticks.
ExampleSemTask1 try get sem g_semId, timeout 10 ticks.
ExampleSemTask1 timeout and try get sem g_semId wait forever.
ExampleSemTask2 get sem g_semId and then delay 20 ticks.
ExampleSemTask2 post sem g_semId.
ExampleSemTask1 wait_forever and get sem g_semId.
ExampleSemTask1 post sem g_semId.
```
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册