未验证 提交 665e2f89 编写于 作者: O openharmony_ci 提交者: Gitee

!14632 同步kernel文档到monthly分支

Merge pull request !14632 from Annie_wang/PRkernel
......@@ -26,6 +26,7 @@
- [Exception Debugging](kernel-mini-memory-exception.md)
- [Trace](kernel-mini-memory-trace.md)
- [LMS](kernel-mini-memory-lms.md)
- [Shell](kernel-mini-debug-shell.md)
- Appendix
- [Kernel Coding Specification](kernel-mini-appx-code.md)
- [Standard Libraries](kernel-mini-appx-lib.md)
......@@ -43,19 +44,19 @@
- Memory Management
- [Heap Memory Management](kernel-small-basic-memory-heap.md)
- [Physical Memory Management](kernel-small-basic-memory-physical.md)
- [Virtual Memory Management](kernel-small-basic-memory-virtual.md)
- [Virtual-to-Physical Mapping](kernel-small-basic-inner-reflect.md)
- [Virtual Memory Management](kernel-small-basic-memory-virtual.md)
- [Virtual-to-Physical Mapping](kernel-small-basic-inner-reflect.md)
- Kernel Communication Mechanisms
- [Event](kernel-small-basic-trans-event.md)
- [Semaphore](kernel-small-basic-trans-semaphore.md)
- [Mutex](kernel-small-basic-trans-mutex.md)
- [Semaphore](kernel-small-basic-trans-semaphore.md)
- [Mutex](kernel-small-basic-trans-mutex.md)
- [Queue](kernel-small-basic-trans-queue.md)
- [RW Lock](kernel-small-basic-trans-rwlock.md)
- [Futex](kernel-small-basic-trans-user-mutex.md)
- [Signal](kernel-small-basic-trans-user-signal.md)
- [Time Management](kernel-small-basic-time.md)
- [Software Timer](kernel-small-basic-softtimer.md)
- [Atomic Operation](kernel-small-basic-atomic.md)
- [Software Timer](kernel-small-basic-softtimer.md)
- [Atomic Operation](kernel-small-basic-atomic.md)
- Extension Components
- [System Call](kernel-small-bundles-system.md)
- [Dynamic Loading and Linking](kernel-small-bundles-linking.md)
......@@ -135,7 +136,7 @@
- [Magic Key](kernel-small-debug-shell-magickey.md)
- [User-Space Exception Information](kernel-small-debug-shell-error.md)
- [Trace](kernel-small-debug-trace.md)
- [Perf](kernel-mini-memory-perf.md)
- [Perf](kernel-small-debug-perf.md)
- [LMS](kernel-small-memory-lms.md)
- [Process Debugging](kernel-small-debug-process-cpu.md)
- Kernel-Mode Memory Debugging
......
......@@ -177,7 +177,7 @@ int main (void) {
// ...
osKernelInitialize(); // Initialize CMSIS-RTOS.
osThreadNew(app_main, NULL, NULL); // Create the main thread of the application.
osThreadNew(app_main, NULL, NULL); // Create the main thread of the application.
osKernelStart(); // Start to execute the thread.
for (;;) {}
}
......@@ -196,14 +196,14 @@ The OpenHarmony kernel uses the **musl libc** library and self-developed APIs an
#### Available APIs
**Table 1** APIs for process management
**Table 11** APIs for process management
| Header File| API| Description|
| -------- | -------- | -------- |
| \#include <stdlib.h> | void abort(void); | Terminates the thread.|
| \#include <assert.h> | void assert(scalar expression); | Terminates the thread if the assertion is false.|
| \#include <pthread.h> | int pthread_cond_destroy(pthread_cond_t *cond); | Destroys a condition variable.|
| \#include <pthread.h> | int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t \*restrict attr); | Initializes a condition variable.|
| \#include <pthread.h> | int pthread_cond_destroy(pthread_cond_t \*cond); | Destroys a condition variable.|
| \#include <pthread.h> | int pthread_cond_init(pthread_cond_t \*restrict cond, const pthread_condattr_t \*restrict attr); | Initializes a condition variable.|
| \#include <pthread.h> | int pthread_cond_timedwait(pthread_cond_t \*restrict cond, pthread_mutex_t \*restrict mutex, const struct timespec \*restrict abstime); | Waits for the condition.|
| \#include <pthread.h> | int pthread_condattr_init(pthread_condattr_t \*attr); | Initializes the condition variable attribute.|
| \#include <pthread.h> | int pthread_mutex_unlock(pthread_mutex_t \*mutex); | Unlocks a mutex.|
......@@ -212,13 +212,13 @@ The OpenHarmony kernel uses the **musl libc** library and self-developed APIs an
| \#include <pthread.h> | pthread_t pthread_self(void); | Obtains the ID of the current thread.|
| \#include <pthread.h> | int pthread_getschedparam(pthread_t thread, int \*policy, struct sched_param \*param); | Obtains the scheduling policy and parameters of a thread.|
| \#include <pthread.h> | int pthread_setschedparam(pthread_t thread, intpolicy, const struct sched_param \*param); | Sets a scheduling policy and parameters for a thread.|
| \#include <pthread.h> | int pthread_mutex_init(pthread_mutex_t \* __restrict m, const pthread_mutexattr_t \*__restrict a); | Initializes a mutex.|
| \#include <pthread.h> | int pthread_mutex_init(pthread_mutex_t *\_restrict m, const pthread_mutexattr_t \*__restrict a); | Initializes a mutex.|
| \#include <pthread.h> | int pthread_mutex_lock(pthread_mutex_t \*m); | Locks a mutex.|
| \#include <pthread.h> | int pthread_mutex_trylock(pthread_mutex_t \*m); | Attempts to lock a mutex.|
| \#include <pthread.h> | int pthread_mutex_destroy(pthread_mutex_t \*m); | Destroys a mutex.|
| \#include <pthread.h> | int pthread_attr_init(pthread_attr_t \*attr); | Initializes a thread attribute object.|
| \#include <pthread.h> | int pthread_attr_destroy(pthread_attr_t \*attr); | Destroys a thread attribute object.|
| \#include <pthread.h> | int pthread_attr_getstacksize(const pthread_attr_t \*attr, size_t \*stacksize); | Obtains the stack size of a thread attribute object.|
| \#include <pthread.h> | int pthread_attr_getstacksize(const pthread_attr*t \*attr, size*t \*stacksize); | Obtains the stack size of a thread attribute object.|
| \#include <pthread.h> | int pthread_attr_setstacksize(pthread_attr_t \*attr, size_t stacksize); | Sets the stack size for a thread attribute object.|
| \#include <pthread.h> | int pthread_attr_getschedparam(const pthread_attr_t \*attr, struct sched_param \*param); | Obtains scheduling parameter attributes of a thread attribute object.|
| \#include <pthread.h> | int pthread_attr_setschedparam(pthread_attr_t \*attr, const struct sched_param \*param); | Sets scheduling parameter attributes for a thread attribute object.|
......@@ -226,9 +226,9 @@ The OpenHarmony kernel uses the **musl libc** library and self-developed APIs an
| \#include <pthread.h> | int pthread_setname_np(pthread_t pthread, constchar \*name); | Sets the thread name.|
| \#include <pthread.h> | int pthread_cond_broadcast(pthread_cond_t \*c); | Unblocks all threads that are currently blocked on the condition variable **cond**.|
| \#include <pthread.h> | int pthread_cond_signal(pthread_cond_t \*c); | Unblocks a thread.|
| \#include <pthread.h> | int pthread_cond_wait(pthread_cond_t \*__restrictc, pthread_mutex_t \*__restrict m); | Waits for the condition.|
| \#include <pthread.h> | int pthread_cond_wait(pthread_cond_t *\__restrictc, pthread_mutex_t \*__restrict m); | Waits for the condition.|
**Table 2** APIs for file system management
**Table 12** APIs for file system management
| Header File| API| Description|
| -------- | -------- | -------- |
......@@ -250,7 +250,7 @@ The OpenHarmony kernel uses the **musl libc** library and self-developed APIs an
| \#include <sys/stat.h> | int fstat(int fd, struct stat \*buf); | Obtains file status.|
| \#include <sys/statfs.h> | int statfs(const char \*path, struct statfs \*buf); | Obtains the file system information for a file in a specified path.|
**Table 3** APIs for time management
**Table 13** APIs for time management
| Header File| API| Description|
| -------- | -------- | -------- |
......@@ -265,19 +265,19 @@ The OpenHarmony kernel uses the **musl libc** library and self-developed APIs an
| \#include <unistd.h> | int usleep(useconds_t usec); | Goes to hibernation, in microseconds.|
| \#include <time.h> | int nanosleep(const struct timespec \*tspec1, structtimespec \*tspec2); | Suspends the current thread till the specified time.|
| \#include <time.h> | int clock_gettime(clockid_t id, struct timespec \*tspec); | Obtains the clock time.|
| \#include <time.h> | int timer_create(clockid_t id, struct sigevent \*__restrict evp, timer_t \*__restrict t); | Creates a timer for a thread.|
| \#include <time.h> | int timer_create(clockid_t id, struct sigevent *\__restrict evp, timer_t \*__restrict t); | Creates a timer for a thread.|
| \#include <time.h> | int timer_delete(timer_t t); | Deletes the timer for a thread.|
| \#include <time.h> | int timer_settime(timer_t t, int flags, const structitimerspec \*__restrict val, struct itimerspec \*__restrict old); | Sets a timer for a thread.|
| \#include <time.h> | int timer_settime(timer_t t, int flags, const struct itimerspec *\__restrict val, struct itimerspec \*_restrict old); | Sets a timer for a thread.|
| \#include <time.h> | time_t time (time_t \*t); | Obtains the time.|
| \#include <time.h> | char \*strptime(const char \*s, const char \*format, struct tm \*tm); | Converts the time string into the time **tm** structure.|
**Table 4** APIs for util
**Table 14** APIs for util
| Header File| API| Description|
| -------- | -------- | -------- |
| \#include <stdlib.h> | int atoi(const char \*nptr); | Converts the string pointed to by **nptr** into an integer (**int** type).|
| \#include <stdlib.h> | long atol(const char \*nptr); | Converts the string pointed to by **nptr** into a long Integer (long type).|
| \#include <stdlib.h> | long long atoll(const char \*nptr); | Converts the string pointed to by **nptr** into a long long Integer (long long type).|
| \#include <stdlib.h> | int atoi(const char \*nptr); | Converts a string into an integer (**int** type).|
| \#include <stdlib.h> | long atol(const char \*nptr); | Converts the string into a long Integer (**long** type).|
| \#include <stdlib.h> | long long atoll(const char \*nptr); | Converts a string into a long longer integer (**long long** type).|
| \#include <ctype.h> | int isalnum(int c); | Checks whether the passed character is alphanumeric.|
| \#include <ctype.h> | int isascii(int c); | Checks whether the passed character is an ASCII character.|
| \#include <ctype.h> | int isdigit(int c); | Checks whether the passed character is a digit.|
......@@ -302,17 +302,17 @@ The OpenHarmony kernel uses the **musl libc** library and self-developed APIs an
| \#include <strings.h> | int strncasecmp(const char \*s1, const char \*s2, size_t n); | Compares the bytes of the specified length in two strings, ignoring case.|
| \#include <strings.h> | int strcasecmp(const char \*s1, const char \*s2); | Compares two strings, ignoring case.|
| \#include <string.h> | int strncmp(const char \*s1, const char \*s2, size_t n); | Compares the bytes of the specified length in two strings.|
| \#include <string.h> | char \*strrchr(const char \*s, int c); | Searches for the last occurrence of a character in a string.|
| \#include <string.h> | char \*strrchr(const char \*s, int c); | Searches for a character in a string.|
| \#include <string.h> | char \*strstr(const char \*haystack, const char \*needle); | Searches for the specified substring in a string.|
| \#include <stdlib.h> | long int strtol(const char \*nptr, char \*\*endptr, int base); | Converts the string pointed to by **nptr** into a **long int** value according to the given **base**.|
| \#include <stdlib.h> | unsigned long int strtoul(const char \*nptr, char\*\*endptr, int base); | Converts the string pointed to by **nptr** into an unsigned long integer.|
| \#include <stdlib.h> | unsigned long long int strtoull(const char \*nptr,char \*\*endptr, int base); | Converts the string pointed to by **nptr** into an unsigned long long integer.|
| \#include <stdlib.h> | unsigned long int strtoul(const char \*nptr, char\*\*endptr, int base); | Converts a string into an unsigned long integer.|
| \#include <stdlib.h> | unsigned long long int strtoull(const char \*nptr,char \*\*endptr,int base); | Converts a string into an unsigned long long integer.|
| \#include <regex.h> | int regcomp(regex_t \*preg, const char \*regex,int cflags); | Compiles a regular expression.|
| \#include <regex.h> | int regexec(const regex_t \*preg, const char \*string, size_t nmatch, regmatch_t pmatch[], int eflags); | Executes the compiled regular expression.|
| \#include <regex.h> | void regfree(regex_t \*preg); | Releases the regular expression.|
| \#include <string.h> | char \*strerror(int errnum); | Obtains an error message string of the specified error code.|
**Table 5** APIs for math operations
**Table 15** APIs for math operations
| Header File| API| Description|
| -------- | -------- | -------- |
......@@ -322,7 +322,7 @@ The OpenHarmony kernel uses the **musl libc** library and self-developed APIs an
| \#include <math.h> | double round(double x); | Rounds off the value from zero to the nearest integer.|
| \#include <math.h> | double sqrt(double x); | Obtains the square root of **x**.|
**Table 6** APIs for I/O operations
**Table 16** APIs for I/O operations
| Header File| API| Description|
| -------- | -------- | -------- |
......@@ -335,16 +335,16 @@ The OpenHarmony kernel uses the **musl libc** library and self-developed APIs an
| \#include <stdio.h> | int fileno(FILE \*stream); | Obtains the file descriptor for a stream.|
| \#include <stdio.h> | FILE \*fopen(const char \*path, const char \*mode); | Opens a stream.|
| \#include <stdio.h> | int fputs(const char \*s, FILE \*stream); | Writes a line to the specified stream.|
| \#include <stdio.h> | size_t fread(void \*ptr, size_t size, size_t nmemb,FILE \*stream); | Reads a stream.|
| \#include <stdio.h> | size_t fread(void \*ptr, size_t size, size_t nmemb, FILE \*stream); | Reads a stream.|
| \#include <stdio.h> | int fseek(FILE \*stream, long offset, int whence); | Sets the position of the stream pointer.|
| \#include <stdio.h> | long ftell(FILE \*stream); | Obtains the position of the stream pointer.|
| \#include <stdio.h> | size_t fwrite(const void \*ptr, size_t size, size_tnmemb,FILE \*stream); | Writes data to a stream.|
| \#include <stdio.h> | size_t fwrite(const void \*ptr, size_t size, size_tnmemb, FILE \*stream); | Writes data to a stream.|
| \#include <stdio.h> | void perror(const char \*s); | Prints system error information.|
| \#include <stdio.h> | void rewind(FILE \*stream); | Sets the position to the beginning of the file of the specified stream.|
| \#include <unistd.h> | ssize_t write(int fd, const void \*buf, size_t size); | Writes data a file.|
| \#include <unistd.h> | ssize_t read(int fd, void \*buf, size_t size); | Reads data from a file.|
**Table 7** APIs for network
**Table 17** APIs for network
| Header File| API| Description|
| -------- | -------- | -------- |
......@@ -363,7 +363,7 @@ The OpenHarmony kernel uses the **musl libc** library and self-developed APIs an
| \#include <sys/socket.h> | ssize_t sendto(int sockfd, const void \*buf, size_t len, intflags,const struct sockaddr \*dest_addr, socklen_t addrlen); | Sends a message on a socket.|
| \#include <sys/socket.h> | int setsockopt(int sockfd, int level, int optname,constvoid \*optval, socklen_t optlen); | Sets options associated with a socket.|
**Table 8** APIs for memory management
**Table 18** APIs for memory management
| Header File| API| Description|
| -------- | -------- | -------- |
......@@ -374,7 +374,7 @@ The OpenHarmony kernel uses the **musl libc** library and self-developed APIs an
| \#include <stdlib.h> | void \*malloc(size_t size); | Dynamically allocates memory blocks.|
| \#include <stdlib.h> | void free(void \*ptr); | Release the memory space pointed to by **ptr**.|
**Table 9** APIs for IPC
**Table 19** APIs for IPC
| Header File| API| Description|
| -------- | -------- | -------- |
......@@ -386,11 +386,11 @@ The OpenHarmony kernel uses the **musl libc** library and self-developed APIs an
| \#include <mqueue.h> | mqd_t mq_open(const char \*mqName, int openFlag, ...); | Opens an existing message queue with the specified name or creates a message queue.|
| \#include <mqueue.h> | int mq_close(mqd_t personal); | Closes a message queue with the specified descriptor.|
| \#include <mqueue.h> | int mq_unlink(const char \*mqName); | Deletes the message queue of the specified name.|
| \#include <mqueue.h> | int mq_send(mqd_t personal, const char \*msg,size_t msgLen, unsigned int msgPrio); | Puts a message with the specified content and length into a message queue.|
| \#include <mqueue.h> | ssize_t mq_receive(mqd_t personal, char \*msg,size_t msgLen, unsigned int \*msgPrio); | Deletes the oldest message from a message queue and puts it in the buffer pointed to by **msg_ptr**.|
| \#include <mqueue.h> | int mq_send(mqd_t personal, const char \*msg, size_t msgLen, unsigned int msgPrio); | Puts a message with the specified content and length into a message queue.|
| \#include <mqueue.h> | ssize_t mq_receive(mqd_t personal, char \*msg, size_t msgLen, unsigned int \*msgPrio); | Deletes the oldest message from a message queue and puts it in the buffer pointed to by **msg_ptr**.|
| \#include <mqueue.h> | int mq_timedsend(mqd_t personal, const char\*msg, size_t msgLen, unsigned int msgPrio, const struct timespec \*absTimeout) | Puts a message with the specified content and length into a message queue at the specified time.|
| \#include <mqueue.h> | ssize_t mq_timedreceive(mqd_t personal, char\*msg, size_t msgLen, unsigned int \*msgPrio, const struct timespec \*absTimeout); | Obtains a message with the specified content and length from a message queue.|
| \#include <mqueue.h> | int mq_setattr(mqd_t mqdes, const struct mq_attr \*__restrict newattr, struct mq_attr \*__restrict oldattr); | Sets the message queue attributes specified by the descriptor.|
| \#include <mqueue.h> | int mq_setattr(mqd_t mqdes, const struct mq_attr \*\_\_restrict newattr, struct mq_attr *\__restrict oldattr); | Sets the message queue attributes specified by the descriptor.|
| \#include <libc.h> | const char \*libc_get_version_string(void); | Obtains the libc version string.|
| \#include <libc.h> | int libc_get_version(void); | Obtains the libc version.|
......@@ -459,6 +459,8 @@ Example:
Creates a thread, transfers the information in the parent thread to the child thread, and prints the transferred information and the thread ID in the child thread.
The sample code can be compiled and verified in **./kernel/liteos_m/testsuites/src/osTest.c**. The **DemoForTest** function is called in **TestTaskEntry**.
```
#include <stdio.h>
......
# 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**.
```
......
# Shell
The shell provided by the OpenHarmony kernel supports basic debugging functions and provides commands related to the system, files, and network. It also supports commands customized based on service requirements.
The shell function is used for debugging only. Currently, it does not support the functions such as tab completion and undo with a key.
Some commands can be used only after the corresponding options are enabled by using **make menuconfig**.
## Common Shell Commands
### cat
Displays the content of a text file. This command can be used only after **LOSCFG_FS_VFS** is enabled.
#### Format
cat [FILE]
#### Parameters
| Parameter| Description | Value Range |
| ---- | ---------- | -------------- |
| FILE | File path.| An existing file.|
### cd
Changes the current directory. This command can be used only after **LOSCFG_FS_VFS** is enabled.
#### Format
cd [path]
#### Parameters
| Parameter| Description | Value Range |
| ---- | ---------- | -------------- |
| path | File path.| Path of the new directory.|
### cp
Copies a file. This command can be used only after **LOSCFG_FS_VFS** is enabled.
#### Format
cp [SOURCEFILE] [DESTFILE]
#### Parameters
| Parameter | Description | Value Range |
| ---------- | -------------- | ----------------------------------------- |
| SOURCEFILE | Path of the file to copy. | Currently, only files are supported. Directories are not supported. The file cannot be empty.|
| DESTFILE | Path of the file created.| Directory and file names are supported. The directory must exist. |
### date
Queries the system date and time.
#### Format
date
#### Parameters
None.
### free
Displays the memory usage of the system.
#### Format
free [ -k | -m ]
#### Parameters
| Parameter| Description | Value Range|
| ---- | ----------------- | -------- |
| -k | Display the memory usage in KiB.| N/A |
| -m | Display the memory usage in MiB.| N/A |
### help
Displays all commands in this operating system.
#### Format
help
#### Parameters
None.
### ifconfig
Displays the IP address, network mask, gateway, and MAC address of a network adapter. This command can be used only after **LWIP_SHELLCMD_ENABLE** is enabled.
#### Format
ifconfig
#### Parameters
None.
### ls
Displays the content of a directory. This command can be used only after **LOSCFG_FS_VFS** is enabled.
#### Format
ls [DIRECTORY]
#### Parameters
| Parameter | Description | Value Range |
| --------- | ---------- | ------------------------------------------------------------ |
| DIRECTORY | Path of the directory.| If **DIRECTORY** is not specified, the content of the current directory is displayed.<br>If **DIRECTORY** is a valid directory, the content of the specified directory is displayed.<br>Currently, LiteOS-M does not support the root directory /.|
### memusage
Displays the memory waterline.
#### Format
memusage [-k/-m]
#### Parameters
| Parameter| Description | Value Range|
| ---- | ----------------- | -------- |
| -k | Display the memory usage in KiB.| N/A |
| -m | Display the memory usage in MiB.| N/A |
### mkdir
Creates a directory. This command can be used only after **LOSCFG_FS_VFS** is enabled.
#### Format
mkdir [DIRECTORY]
#### Parameters
| Parameter | Description | Value Range |
| --------- | ---------- | ------------------------------------- |
| DIRECTORY | Path of the directory.| The value of **DIRECTORY** can be an absolute path or a relative path.|
### ping
Checks whether the network is connected. This command can be used only after **LWIP_SHELLCMD_ENABLE** is enabled.
#### Format
ping [ip]
#### Parameters
| Parameter| Description | Value Range|
| ---- | ------------------------------ | -------- |
| ip | IPv4 address of the network to test.| N/A |
### pwd
Displays the current path. This command can be used only after **LOSCFG_FS_VFS** is enabled.
#### Format
pwd
### rm
Deletes a file or folder. This command can be used only after **LOSCFG_FS_VFS** is enabled.
#### Format
rm [FILE] or rm [-r/-R] [FILE]
#### Parameters
| Parameter | Description | Value Range |
| ----- | ------------------------------- | -------------------------------- |
| FILE | File or folder name.| The value of **FILE** can be an absolute path or a relative path.|
| -r/-R | If **FILE** is a folder, -r/-R needs to be set. | N/A |
### rmdir
Deletes a folder. This command can be used only after **LOSCFG_FS_VFS** is enabled.
#### Format
rmdir [DIRECTORY]
#### Parameters
| Parameter | Description | Value Range |
| --------- | ---------- | ------------------------------------- |
| DIRECTORY | Path of the directory.| The value of **DIRECTORY** can be an absolute path or a relative path.|
### task
Displays the status of each task.
#### Format
task
The displayed information includes the task No., priority, status, stack information, signal, event, CPU usage, and task name.
### touch
Creates a file. This command can be used only after **LOSCFG_FS_VFS** is enabled.
#### Format
touch [FILE]
#### Parameters
| Parameter| Description| Value Range |
| ---- | -------- | -------------------------------- |
| FILE | File name.| The value of **FILE** can be an absolute path or a relative path.|
### stack
Displays the stack information of a task. This command can be used only after **LOSCFG_DEBUG_TOOLS** is enabled. Enabling this function affects the performance.
#### Format
stack [ID]
#### Parameters
| Parameter| Description| Value Range |
| ---- | -------- | ------------------------ |
| ID | Task ID.| The task corresponding to the task ID must exist.|
### hwi
Queries the interrupt usage. This command can be used only after **LOSCFG_DEBUG_TOOLS** is enabled. Enabling this function affects the performance.
#### Format
hwi
### st
Queries scheduling information. This command can be used only afterf **LOSCFG_DEBUG_TOOLS** is enabled. Enabling this function affects the performance.
#### Format
st -s | st -e
#### Parameters
| Parameter| Description | Value Range|
| ---- | ---------------------- | -------- |
| -s | Start to record scheduling information. | N/A |
| -e | Stop recording and print scheduling information.| N/A |
# CPUP
## Basic Concepts
The central processing unit percent \(CPUP\) includes the system CPUP and task CPUP.
The central processing unit percent (CPUP) includes the system CPUP and task CPUP.
The system CPUP is the CPU usage of the system within a period of time. It reflects the CPU load and the system running status \(idle or busy\) in the given period of time. The valid range of the system CPUP is 0 to 100 in percentage. The precision can be adjusted through configuration. The value **100** indicates that the system runs with full load.
**System CPUP**
Task CPUP refers to the CPU usage of a single task. It reflects the task status, busy or idle, in a period of time. The valid range of task CPUP is 0 to 100 in percentage. The precision can be adjusted through configuration. The value **100** indicates that the task is being executed for the given period of time.
The system CPUP is the CPU usage of the system within a period of time. It reflects the CPU load and the system running status (idle or busy) in the given period of time. The CPUP ranges from 0 to 100, in percentage. The value **100** indicates that the system runs with full load.
With the system CPUP, you can determine whether the current system load exceeds the designed specifications.
**Task CPUP**
Task CPUP refers to the CPU usage of a single task. It reflects the task status, busy or idle, in a period of time. The task CPUP ranges from 0 to 100, in percentage. The value **100** indicates that the task is being executed for the given period of time.
With the CPUP of each task, you can determine whether the CPU usage of each task meets expectations of the design.
**Interrupt CPUP**
In addition, you can enable the interrupt usage statistics function after the CPUP function is enabled.
Interrupt CPUP indicates the CPU usage of a single interrupt out of the total interrupt duration. The interrupt CPUP ranges from 0 to 100. The value **100** indicates that only the interrupt is triggered within a period of time.
## Working Principles
The OpenHarmony LiteOS-M CPUP records the system CPU usage on a task basis. When task switching occurs, the task start time and task switch-out or exit time are recorded. Each time when a task exits, the system accumulates the CPU time used by the task.
You can configure this function in **target\_config.h**.
You can configure this function in **target_config.h**.
The OpenHarmony LiteOS-M provides the following types of CPUP information:
- System CPUP
- Task CPUP
- System CPUP
- Task CPUP
In addition, the system provides the capability of querying the interrupt CPUP (the CPUP and timer must be enabled).
The CPUP is calculated as follows:
......@@ -29,156 +43,148 @@ System CPUP = Total running time of all tasks except idle tasks/Total running ti
Task CPUP = Total running time of the task/Total running time of the system
## Available APIs<a name="section158501652121514"></a>
**Table 1** Functions
<a name="table18293928155615"></a>
<table><thead align="left"><tr id="row129362875613"><th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.1"><p id="p19444103765618"><a name="p19444103765618"></a><a name="p19444103765618"></a>Function</p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.2"><p id="p944473716569"><a name="p944473716569"></a><a name="p944473716569"></a>API</p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.3"><p id="p144445378565"><a name="p144445378565"></a><a name="p144445378565"></a>Description</p>
</th>
</tr>
</thead>
<tbody><tr id="row1143613475615"><td class="cellrowborder" rowspan="2" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p942993405610"><a name="p942993405610"></a><a name="p942993405610"></a>Obtaining the system CPU usage</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p242973419563"><a name="p242973419563"></a><a name="p242973419563"></a>LOS_SysCpuUsage</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p7429163416565"><a name="p7429163416565"></a><a name="p7429163416565"></a>Obtains the current system CPUP.</p>
</td>
</tr>
<tr id="row15436163435611"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p20429183410563"><a name="p20429183410563"></a><a name="p20429183410563"></a>LOS_HistorySysCpuUsage</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p542953465617"><a name="p542953465617"></a><a name="p542953465617"></a>Obtains the historical CPUP of the system.</p>
</td>
</tr>
<tr id="row143610342562"><td class="cellrowborder" rowspan="3" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p174295347568"><a name="p174295347568"></a><a name="p174295347568"></a>Obtaining the task CPUP</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p124291734155614"><a name="p124291734155614"></a><a name="p124291734155614"></a>LOS_TaskCpuUsage</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p1042963410568"><a name="p1042963410568"></a><a name="p1042963410568"></a>Obtains the CPUP of a specified task.</p>
</td>
</tr>
<tr id="row12436143414561"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p6429834185613"><a name="p6429834185613"></a><a name="p6429834185613"></a>LOS_HistoryTaskCpuUsage</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p74302034175614"><a name="p74302034175614"></a><a name="p74302034175614"></a>Obtains the historical CPUP of a specified task.</p>
</td>
</tr>
<tr id="row2435834135618"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p843073420563"><a name="p843073420563"></a><a name="p843073420563"></a>LOS_AllCpuUsage</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p4430134185614"><a name="p4430134185614"></a><a name="p4430134185614"></a>Obtains the CPUP of all tasks.</p>
</td>
</tr>
<tr id="row15435934155618"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p1543033435615"><a name="p1543033435615"></a><a name="p1543033435615"></a>Outputting the task CPUP</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p1643016342562"><a name="p1643016342562"></a><a name="p1643016342562"></a>LOS_CpupUsageMonitor</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p84301234115617"><a name="p84301234115617"></a><a name="p84301234115617"></a>Outputs the historical CPUP of a task.</p>
</td>
</tr>
</tbody>
</table>
Interrupt CPUP = Running time of a single interrupt/Total running time of all interrupts
## Available APIs
**Table 1** APIs for CPUP
| Category| Description|
| -------- | -------- |
| Obtaining the system CPUP| **LOS_SysCpuUsage**: obtains the current system CPUP.<br>**LOS_HistorySysCpuUsage**: obtains the historical CPUP of the system.|
| Obtaining the task CPUP| **LOS_TaskCpuUsage**: obtains the CPUP of a task.<br>**LOS_HistoryTaskCpuUsage**: obtains the historical CPUP of a task.<br>**LOS_AllTaskCpuUsage**: obtains the CPUP of all tasks.|
| Outputting the task CPUP| **LOS_CpupUsageMonitor**: outputs the historical CPUP of a task.|
| Obtaining the interrupt CPUP| **LOS_GetAllIrqCpuUsage**: obtains the CPUP of all interrupts.|
## How to Develop
In the **kernel/liteos_m** directory, run the **make menuconfig** command and choose **Kernel > Enable Cpup** to enable CPUP.
Choose **Enable Cpup include irq** to enable interrupt CPUP.
The typical CPUP development process is as follows:
1. Call **LOS\_SysCpuUsage** to obtain the system CPUP.
2. Call **LOS\_HistorySysCpuUsage** to obtain the historical CPUP of the system.
3. Call **LOS\_TaskCpuUsage** to obtain the CPUP of a specified task.
- If the task has been created, disable interrupt, obtain the CPUP, and then enable interrupt.
- If the task is not created, return an error code.
1. Call **LOS_SysCpuUsage** to obtain the system CPUP.
2. Call **LOS_HistorySysCpuUsage** to obtain the historical CPUP of the system.
4. Call **LOS\_HistoryTaskCpuUsage** to obtain the historical CPUP of a specified task.
- If the task has been created, disable interrupt, obtain the CPUP in different modes, and then enable interrupt.
- If the task is not created, return an error code.
3. Call **LOS_TaskCpuUsage** to obtain the CPUP of a task.
- If the task has been created, disable interrupt, obtain the CPUP, and then enable interrupt.
- If the task is not created, return an error code.
5. Call **LOS\_AllCpuUsage** to obtain the CPUP of all tasks.
- If the CPUP is initialized, disable interrupt, obtain the CPUP in different modes, and then enable interrupt.
- If CPUP is not initialized or has invalid input parameters, return an error code.
4. Call **LOS_HistoryTaskCpuUsage** to obtain the historical CPUP of a task.
- If the task has been created, disable interrupt, obtain the CPUP in different modes, and then enable interrupt.
- If the task is not created, return an error code.
5. Call **LOS_AllCpuUsage** to obtain the CPUP of all tasks.
- If CPUP has been initialized, disable interrupt, obtain the CPUP in different modes, and then enable interrupt.
- If CPUP is not initialized or has invalid input parameters, return an error code.
## Development Example
### Example Description
This example implements the following:
1. Create a task for the CPUP test.
2. Obtain the CPUP of the current system.
3. Obtain the historical system CPUP in different modes.
4. Obtain the CPUP of the created test task.
5. Obtain the CPUP of the created test task in different modes.
1. Create a task for the CPUP test.
2. Obtain the CPUP of the current system.
3. Obtain the historical system CPUP in different modes.
4. Obtain the CPUP of the created task.
5. Obtain the CPUP of the created task in different modes.
### Sample Code
Prerequisites
**Prerequisites**
In **target\_config.h**, the **LOSCFG\_BASE\_CORE\_CPUP** parameter is enabled.
CPUP is enabled.<br>To enable CPUP, run **make menuconfig** in the **kernel/liteos_m** directory and choose **Kernel->Enable Cpup** to enable CPUP.
The sample code is as follows:
The sample code can be compiled and verified in **./kernel/liteos_m/testsuites/src/osTest.c**. The **ExampleCpup** function is called in **TestTaskEntry**.
```
#include "los_task.h"
#include "los_cpup.h"
#define MODE 4
UINT32 g_cpuTestTaskID;
VOID ExampleCpup(VOID)
{
#include "los_cpup.h"
#define TEST_TASK_PRIO 5
#define TASK_DELAY_TIME 100
VOID CpupTask(VOID)
{
printf("entry cpup test example\n");
while(1) {
usleep(100);
}
usleep(TASK_DELAY_TIME);
usleep(TASK_DELAY_TIME);
printf("exit cpup test example\n");
}
UINT32 ItCpupTest(VOID)
{
UINT32 ExampleCpup(VOID)
{
UINT32 ret;
UINT32 cpupUse;
UINT32 taskID;
TSK_INIT_PARAM_S cpupTestTask = { 0 };
memset(&cpupTestTask, 0, sizeof(TSK_INIT_PARAM_S));
cpupTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleCpup;
cpupTestTask.pcName = "TestCpupTsk";
cpupTestTask.uwStackSize = 0x800;
cpupTestTask.usTaskPrio = 5;
ret = LOS_TaskCreate(&g_cpuTestTaskID, &cpupTestTask);
cpupTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)CpupTask;
cpupTestTask.pcName = "TestCpupTsk";
cpupTestTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
cpupTestTask.usTaskPrio = TEST_TASK_PRIO;
ret = LOS_TaskCreate(&taskID, &cpupTestTask);
if(ret != LOS_OK) {
printf("cpupTestTask create failed .\n");
return LOS_NOK;
}
usleep(100);
usleep(TASK_DELAY_TIME);
/* Obtain the current CPUP of the system. */
/* Obtain the current system CPUP. */
cpupUse = LOS_SysCpuUsage();
printf("the current system cpu usage is: %u.%u\n",
cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT);
cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT);
cpupUse = LOS_HistorySysCpuUsage(CPU_LESS_THAN_1S);
/* Obtain the CPUP of the specified task (cpupTestTask in this example).*/
printf("the history system CPUP in all time: %u.%u\n",
/* Obtain the historical CPUP of the system. */
cpupUse = LOS_HistorySysCpuUsage(CPUP_LESS_THAN_1S);
printf("the history system cpu usage in all time: %u.%u\n",
cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT);
cpupUse = LOS_TaskCpuUsage(g_cpuTestTaskID);
/* Obtain the CPUP of the specified historical task (cpupTestTask in this example) since the system startup. */
/* Obtain the CPUP of a specified task. */
cpupUse = LOS_TaskCpuUsage(taskID);
printf("cpu usage of the cpupTestTask:\n TaskID: %d\n usage: %u.%u\n",
g_cpuTestTaskID, cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT);
cpupUse = LOS_HistoryTaskCpuUsage(g_cpuTestTaskID, CPU_LESS_THAN_1S);
taskID, cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT);
/* Obtain the CPUP of a specified task since the system starts. */
cpupUse = LOS_HistoryTaskCpuUsage(taskID, CPUP_LESS_THAN_1S);
printf("cpu usage of the cpupTestTask in all time:\n TaskID: %d\n usage: %u.%u\n",
g_cpuTestTaskID, cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT);
return LOS_OK;
taskID, cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT);
return LOS_OK;
}
```
### Verification
The development is successful if the return result is as follows:
The development is successful if the return result is as follows:
```
entry cpup test example
the current system cpu usage is : 1.5
the history system cpu usage in all time: 3.0
cpu usage of the cpupTestTask: TaskID:10 usage: 0.0
cpu usage of the cpupTestTask&nbsp;in all time: TaskID:10 usage: 0.0
entry cpup test example
the current system cpu usage is: 8.2
the history system cpu usage in all time: 8.9
cpu usage of the cpupTestTask:
TaskID: 5
usage: 0.5
cpu usage of the cpupTestTask in all time:
TaskID: 5
usage: 0.5
exit cpup test example
The preceding data may vary depending on the running environment.
```
......@@ -11,16 +11,16 @@ The purpose of memory debugging is to locate problems related to dynamic memory.
Memory information includes the memory pool size, memory usage, remaining memory size, maximum free memory, memory waterline, number of memory nodes, and fragmentation rate.
- Memory waterline: indicates the maximum memory used in a memory pool. The waterline value is updated upon each memory allocation and release. The memory pool size can be optimized based on this value.
- Memory waterline indicates the maximum memory used in a memory pool. The waterline value is updated upon each memory allocation and release. The memory pool size can be optimized based on this value.
- Fragmentation rate: indicates the fragmentation degree of the memory pool. If the fragmentation rate is high, there are a large number of free memory blocks in the memory pool but each block is small. You can use the following formula to calculate the fragmentation rate:<br>Fragmentation rate = 100 – 100 x Maximum free memory block size/Remaining memory size
- Fragmentation rate indicates the fragmentation degree of the memory pool. If the fragmentation rate is high, there are a large number of free memory blocks in the memory pool but each block is small. You can use the following formula to calculate the fragmentation rate:<br>Fragmentation rate = 100 – 100 x Maximum free memory block size/Remaining memory size
- Other parameters: You can call APIs described in [Memory Management](../kernel/kernel-mini-basic-memory.md) to scan node information in the memory pool and collect statistics.
- You can use [APIs for memory management](kernel-mini-basic-memory.md) to scan node information in the memory pool and collect statistics.
### Function Configuration
**LOSCFG_MEM_WATERLINE**: specifies the setting of the memory information statistics function. This function is enabled by default. To disable the function, set this macro to **0** in **target_config.h**. If you want to obtain the memory waterline, you must enable this macro.
**LOSCFG_MEM_WATERLINE** specifies the setting of the memory information statistics function. This function is enabled by default. To disable the function, set this macro to **0** in **target_config.h**. If you want to obtain the memory waterline, you must enable this macro.
### Development Guidelines
......@@ -33,20 +33,20 @@ Key structure:
```
typedef struct {
UINT32 totalUsedSize; // Memory usage of the memory pool.
UINT32 totalFreeSize; // Remaining size of the memory pool.
UINT32 maxFreeNodeSize; // Maximum size of the free memory block in the memory pool.
UINT32 usedNodeNum; // Number of non-free memory blocks in the memory pool.
UINT32 freeNodeNum; // Number of free memory blocks in the memory pool.
#if (LOSCFG_MEM_WATERLINE == 1) //The function is enabled by default. To disable it, set this macro to 0 in target_config.h.
UINT32 usageWaterLine; // Waterline of the memory pool.
UINT32 totalUsedSize; // Memory usage of the memory pool.
UINT32 totalFreeSize; // Remaining size of the memory pool.
UINT32 maxFreeNodeSize; // Maximum size of the free memory block in the memory pool.
UINT32 usedNodeNum; // Number of non-free memory blocks in the memory pool.
UINT32 freeNodeNum; // Number of free memory blocks in the memory pool.
#if (LOSCFG_MEM_WATERLINE == 1) // The function is enabled by default. To disable it, set this macro to 0 in target_config.h.
UINT32 usageWaterLine; // Waterline of the memory pool.
#endif
} LOS_MEM_POOL_STATUS;
```
- To obtain the memory waterline, call **LOS_MemInfoGet**. The first parameter in the API is the start address of the memory pool, and the second parameter is the handle of the **LOS_MEM_POOL_STATUS** type. The **usageWaterLine** field indicates the waterline.
To obtain the memory waterline, call **LOS_MemInfoGet**. The first parameter in the API is the start address of the memory pool, and the second parameter is the handle of the **LOS_MEM_POOL_STATUS** type. The **usageWaterLine** field indicates the waterline.
- To calculate the memory fragmentation rate, call **LOS_MemInfoGet** to obtain the remaining memory size and the maximum free memory block size in the memory pool, and then calculate the fragmentation rate of the dynamic memory pool as follows:<br>Fragmentation rate = 100 – 100 x Maximum free memory block size/Remaining memory size
To calculate the memory fragmentation rate, call **LOS_MemInfoGet** to obtain the remaining memory size and the maximum free memory block size in the memory pool, and then calculate the fragmentation rate of the dynamic memory pool as follows:<br>Fragmentation rate = 100 – 100 x Maximum free memory block size/Remaining memory size
#### Development Example
......@@ -62,7 +62,9 @@ This example implements the following:
#### Sample Code
The sample code is as follows:
The sample code is as follows:
The sample code can be compiled and verified in **./kernel/liteos_m/testsuites/src/osTest.c**. The **MemTest** function is called in **TestTaskEntry**.
```
#include <stdio.h>
......@@ -71,20 +73,20 @@ This example implements the following:
#include "los_memory.h"
#include "los_config.h"
#define TEST_TASK_PRIO 5
void MemInfoTaskFunc(void)
{
LOS_MEM_POOL_STATUS poolStatus = {0};
/* pool is the memory address of the information to be collected. OS_SYS_MEM_ADDR is used as an example. */
/* pool is the memory address of the information to be collected. OS_SYS_MEM_ADDR is used as an example. */
void *pool = OS_SYS_MEM_ADDR;
LOS_MemInfoGet(pool, &poolStatus);
/* Calculate the fragmentation rate of the memory pool. */
unsigned char fragment = 100 - poolStatus.maxFreeNodeSize * 100 / poolStatus.totalFreeSize;
float fragment = 100 - poolStatus.maxFreeNodeSize * 100.0 / poolStatus.totalFreeSize;
/* Calculate the memory usage of the memory pool. */
unsigned char usage = LOS_MemTotalUsedGet(pool) * 100 / LOS_MemPoolSizeGet(pool);
printf("usage = %d, fragment = %d, maxFreeSize = %d, totalFreeSize = %d, waterLine = %d\n", usage, fragment, poolStatus.maxFreeNodeSize,
poolStatus.totalFreeSize, poolStatus.usageWaterLine);
float usage = LOS_MemTotalUsedGet(pool) * 100.0 / LOS_MemPoolSizeGet(pool);
printf("usage = %f, fragment = %f, maxFreeSize = %d, totalFreeSize = %d, waterLine = %d\n", usage, fragment,
poolStatus.maxFreeNodeSize, poolStatus.totalFreeSize, poolStatus.usageWaterLine);
}
int MemTest(void)
......@@ -93,9 +95,9 @@ int MemTest(void)
unsigned int taskID;
TSK_INIT_PARAM_S taskStatus = {0};
taskStatus.pfnTaskEntry = (TSK_ENTRY_FUNC)MemInfoTaskFunc;
taskStatus.uwStackSize = 0x1000;
taskStatus.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
taskStatus.pcName = "memInfo";
taskStatus.usTaskPrio = 10;
taskStatus.usTaskPrio = TEST_TASK_PRIO;
ret = LOS_TaskCreate(&taskID, &taskStatus);
if (ret != LOS_OK) {
printf("task create failed\n");
......@@ -112,7 +114,9 @@ The result is as follows:
```
usage = 22, fragment = 3, maxFreeSize = 49056, totalFreeSize = 50132, waterLine = 1414
usage = 0.458344, fragment = 0.000000, maxFreeSize = 16474928, totalFreeSize = 16474928, waterLine = 76816
The preceding data may vary depending on the running environment.
```
## Memory Leak Check
......@@ -124,14 +128,15 @@ As an optional function of the kernel, memory leak check is used to locate dynam
### Function Configuration
1. **LOSCFG_MEM_LEAKCHECK**: specifies the setting of the memory leak check. This function is disabled by default. To enable the function, set this macro to **1** in **target_config.h**.
**LOSCFG_MEM_LEAKCHECK** specifies the setting of the memory leak check. This function is disabled by default. To enable the function, set this macro to **1** in **target_config.h**.
2. **LOSCFG_MEM_RECORD_LR_CNT**: specifies the number of LRs recorded. The default value is **3**. Each LR consumes the memory of **sizeof(void\*)** bytes.
**LOSCFG_MEM_RECORD_LR_CNT** specifies the number of LRs recorded. The default value is **3**. Each LR consumes the memory of **sizeof(void \*)** bytes.
3. **LOSCFG_MEM_OMIT_LR_CNT**: specifies the number of ignored LRs. The default value is **4**, which indicates that LRs are recorded from the time when **LOS_MemAlloc** is called. You can change the value based on actual requirements. This macro is configured because:
- **LOS_MemAlloc** is also called internally.
- **LOS_MemAlloc** may be encapsulated externally.
- The number of LRs configured by **LOSCFG_MEM_RECORD_LR_CNT** is limited.
**LOSCFG_MEM_OMIT_LR_CNT** specifies the number of ignored LRs. The default value is **4**, which indicates that LRs are recorded from the time when **LOS_MemAlloc** is called. You can change the value based on actual requirements. This macro is configured because:
- **LOS_MemAlloc** is also called internally.
- **LOS_MemAlloc** may be encapsulated externally.
- The number of LRs configured by **LOSCFG_MEM_RECORD_LR_CNT** is limited.
Correctly setting this macro can ignore invalid LRs and reduce memory consumption.
......@@ -156,7 +161,8 @@ node size LR[0] LR[1] LR[2]
0x100179cc: 0x5c 0x9b02c24e 0x9b02c246 0x9b008ef0
```
> ![icon-caution.gif](../public_sys-resources/icon-caution.gif) **CAUTION**<br/>
> **CAUTION**
>
> Enabling memory leak check affects memory application performance. LR addresses will be recorded for each memory node, increasing memory overhead.
......@@ -179,6 +185,12 @@ This example implements the following:
The sample code is as follows:
The sample code can be compiled and verified in **./kernel/liteos_m/testsuites/src/osTest.c**. The **MemLeakTest** function is called in **TestTaskEntry**.
When QEMU is running, ensure that the value of **LOSCFG_MEM_FREE_BY_TASKID** in **target_config.h** is **0**.
After the memory check function is enabled, other tasks running on certain platforms may frequently print memory-related information such as "psp, start = xxxxx, end = xxxxxxx". Ignore the information or delete the print information called by **OsStackAddrGet**.
```
#include <stdio.h>
......@@ -216,7 +228,9 @@ node size LR[0] LR[1] LR[2]
0x20002594: 0x120 0x08000e0c 0x08000e56 0x08000c8a
0x20002aac: 0x56 0x08000e0c 0x08000e56 0x08004220
0x20003ac4: 0x1d 0x08001458 0x080014e0 0x080041e6
0x20003ae0: 0x1d 0x080041ee 0x08000cc2 0x00000000
0x20003ae0: 0x1d 0x080041ee 0x08000cc2 0x00000000
The preceding data may vary depending on the running environment.
```
The difference between the two logs is as follows. The following memory nodes are suspected to have blocks with a memory leak.
......@@ -224,7 +238,9 @@ The difference between the two logs is as follows. The following memory nodes ar
```
0x20003ac4: 0x1d 0x08001458 0x080014e0 0x080041e6
0x20003ae0: 0x1d 0x080041ee 0x08000cc2 0x00000000
0x20003ae0: 0x1d 0x080041ee 0x08000cc2 0x00000000
The preceding data may vary depending on the running environment.
```
The following is part of the assembly file:
......@@ -246,6 +262,8 @@ The following is part of the assembly file:
0x80041f0: 0xf7fd 0xf933 BL LOS_MemUsedNodeShow ; 0x800145a
0x80041f4: 0xbd10 POP {R4, PC}
0x80041f6: 0x0000 MOVS R0, R0
The preceding data may vary depending on the running environment.
```
The memory node addressed by **0x080041ee** is not released after being requested in **MemLeakTest**.
......@@ -260,15 +278,16 @@ As an optional function of the kernel, memory corruption check is used to check
### Function Configuration
**LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK**: specifies the setting of the memory corruption check. This function is disabled by default. To enable the function, set this macro to **1** in **target_config.h**.
**LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK** specifies the setting of the memory corruption check. This function is disabled by default. To enable the function, set this macro to **1** in **target_config.h**.
1. If this macro is enabled, the memory pool integrity will be checked in real time upon each memory allocation.
2. If this macro is not enabled, you can call **LOS_MemIntegrityCheck** to check the memory pool integrity when required. Using **LOS_MemIntegrityCheck** does not affect the system performance. In addition, the check accuracy decreases because the node header does not contain the magic number (which is available only when **LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK** is enabled).
2. If this macro is not enabled, you can call **LOS_MemIntegrityCheck** to check the memory pool integrity when required. Using **LOS_MemIntegrityCheck** does not affect the system performance. However, the check accuracy decreases because the node header does not contain the magic number (which is available only when **LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK** is enabled).
This check only detects the corrupted memory node and provides information about the previous node (because memory is contiguous, a node is most likely corrupted by the previous node). To further determine the location where the previous node is requested, you need to enable the memory leak check and use LRs to locate the fault.
> ![icon-caution.gif](../public_sys-resources/icon-caution.gif) **CAUTION**<br/>
> **CAUTION**
>
> If memory corruption check is enabled, a magic number is added to the node header, which increases the size of the node header. The real-time integrity check has a great impact on the performance. In performance-sensitive scenarios, you are advised to disable this function and use **LOS_MemIntegrityCheck** to check the memory pool integrity.
......@@ -295,6 +314,12 @@ This example implements the following:
The sample code is as follows:
The sample code can be compiled and verified in **./kernel/liteos_m/testsuites/src/osTest.c**. The **MemIntegrityTest** function is called in **TestTaskEntry**.
When QEMU is running, ensure that the value of **LOSCFG_MEM_FREE_BY_TASKID** in **target_config.h** is **0**.
Because the exception is triggered intentionally, you need to restart QEMU when the execution is complete. For example, open a new terminal and run **killall qemu-system-arm**.
```
#include <stdio.h>
......@@ -320,20 +345,28 @@ The log is as follows:
```
[ERR][OsMemMagicCheckPrint], 2028, memory check error!
memory used but magic num wrong, magic num = 0x00000000 /* Error information, indicating that the first four bytes, that is, the magic number, of the next node are corrupted. */
broken node head: 0x20003af0 0x00000000 0x80000020, prev node head: 0x20002ad4 0xabcddcba 0x80000020
/* Key information about the corrupted node and its previous node, including the address of the previous node, magic number of the node, and sizeAndFlag of the node. In this example, the magic number of the corrupted node is cleared. */
broken node head LR info: /* The node LR information can be output only after the memory leak check is enabled. */
LR[0]:0x0800414e
LR[1]:0x08000cc2
LR[2]:0x00000000
pre node head LR info: /* Based on the LR information, you can find where the previous node is requested in the assembly file and then perform further analysis. */
LR[0]:0x08004144
LR[1]:0x08000cc2
LR[2]:0x00000000
[ERR]Memory integrity check error, cur node: 0x20003b10, pre node: 0x20003af0 /* Addresses of the corrupted node and its previous node */
/* Error information indicating the field corrupted. In this example, the first four bytes of the next node are cleared, that is, the magic number field is corrupted. */
[ERR][IT_TST_INI][OsMemMagicCheckPrint], 1664, memory check error!
memory used but magic num wrong, magic num = 0x0
/* Key information about the corrupted node and its previous node, including the address of the previous node, magic number of the node, and sizeAndFlag of the node. In this example, the magic number of the corrupted node is cleared. */
broken node head: 0x2103d7e8 0x0 0x80000020, prev node head: 0x2103c7cc 0xabcddcba 0x80000020
/*The node LR information can be output only after the memory leak check is enabled. */
broken node head LR info:
LR[0]:0x2101906c
LR[1]:0x0
LR[2]:0x0
/* Based on the LR information, you can determine where the previous node in requsted in the assembly file and check the use of the node. */
pre node head LR info:
LR[0]:0x2101906c
LR[1]:0x0
LR[2]:0x0
/* Addresses of the corrupted node and its previous node. */
[ERR][IT_TST_INI]Memory integrity check error, cur node: 0x2103d784, pre node: 0x0
The preceding data may vary depending on the running environment.
```
# 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.
3. Set a flag bit to **0**.
4. Obtain the least significant bit of the flag bit 1.
1. Set a flag bit to **1**.
2. Obtain the MSB of flag bit 1.
3. Set a flag bit to **0**.
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,17 +51,17 @@ 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;
}
/* The value of g_startNum is increased by 1. The value indicates the number of child threads that have acquired a mutex. */
g_startNum++;
/* Wait for the cond variable. */
/* 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.
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.
**Example**
**h2****Sample Code**
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[])
......@@ -252,27 +254,32 @@ int main(int argc, char *argv[])
}
...
munmap(addr, length);
close(fd); /* Close fd after the munmap is canceled. */
close(fd); /* Close fd after the munmap is canceled. */
exit(EXIT_SUCCESS);
}
```
### 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.
- 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.
- The default behavior for signals does not include **STOP**, **CONTINUE**, or **COREDUMP**.
### Time
- 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.
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.
- 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 invoked only once even if the same signal is received multiple times.
### 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.
......@@ -3,216 +3,98 @@
## Basic Concepts
In an OS that supports multiple tasks, modifying data in a memory area requires three steps: read data, modify data, and write data. However, data in a memory area may be simultaneously accessed by multiple tasks. If the data modification is interrupted by another task, the execution result of the operation is unpredictable.
In an OS that supports multiple tasks, modifying data in memory involves three steps: read data, modify data, and write data. However, the data may be simultaneously accessed by multiple tasks. If the data modification is interrupted by another task, an unexpected result will be caused.
Although you can enable or disable interrupts to ensure that the multi-task execution results meet expectations, the system performance is affected.
Although you can enable or disable interrupts to ensure expected results of multiple tasks, the system performance is affected.
The ARMv6 architecture has introduced the **LDREX** and **STREX** instructions to support more discreet non-blocking synchronization of the shared memory. The atomic operations implemented thereby can ensure that the "read-modify-write" operations on the same data will not be interrupted, that is, the operation atomicity is ensured.
The ARMv6 architecture has introduced the **LDREX** and **STREX** instructions to support more discreet non-blocking synchronization of the shared memory. The atomic operations implemented thereby can ensure that the "read-modify-write" operations on the same data will not be interrupted, that is, the operation atomicity is ensured.
## Working Principles
The OpenHarmony system has encapsulated the **LDREX** and **STREX** in the ARMv6 architecture to provide a set of atomic operation APIs.
- LDREX Rx, \[Ry\]
Reads the value in the memory and marks the exclusive access to the memory segment.
- Reads the 4-byte memory data pointed by the register **Ry** and saves the data to the **Rx** register.
- Adds an exclusive access flag to the memory area pointed by **Ry**.
- STREX Rf, Rx, \[Ry\]
Checks whether the memory has an exclusive access flag. If yes, the system updates the memory value and clears the flag. If no, the memory is not updated.
## Working Principles
- If there is an exclusive access flag, the system:
- Updates the **Rx** register value to the memory pointed to by the **Ry** register.
- Sets the **Rf** register to **0**.
OpenHarmony has encapsulated the **LDREX** and **STREX** in the ARMv6 architecture to provide a set of atomic operation APIs.
- If there is no exclusive access flag:
- The memory is not updated.
- The system sets the **Rf** register to **1**.
- LDREX Rx, [Ry]
Reads the value in the memory and marks the exclusive access to the memory segment.
- Reads the 4-byte memory data pointed by the register **Ry** and saves the data to the **Rx** register.
- Adds an exclusive access flag to the memory area pointed by **Ry**.
- STREX Rf, Rx, [Ry]
Checks whether the memory has an exclusive access flag. If yes, the system updates the memory value and clears the flag. If no, the memory is not updated.
- If there is an exclusive access flag, the system:
- Updates the **Rx** register value to the memory pointed to by the **Ry** register.
- Sets the **Rf** register to **0**.
- If there is no exclusive access flag:
- The memory is not updated.
- The system sets the **Rf** register to **1**.
- Flag register
- If the flag register is **0**, the system exits the loop and the atomic operation is complete.
- If the flag register is **1**, the system continues the loop and performs the atomic operation again.
- Flag register
- If the flag register is **0**, the system exits the loop and the atomic operation is complete.
- If the flag register is **1**, the system continues the loop and performs the atomic operation again.
## Development Guidelines
### Available APIs
The following table describes the APIs available for the OpenHarmony LiteOS-A kernel atomic operation module. For more details about the APIs, see the API reference.
**Table 1** Atomic operation APIs
<a name="table29217519171"></a>
<table><thead align="left"><tr id="row79375119172"><th class="cellrowborder" valign="top" width="21.21212121212121%" id="mcps1.2.4.1.1"><p id="p159375113174"><a name="p159375113174"></a><a name="p159375113174"></a>Function</p>
</th>
<th class="cellrowborder" valign="top" width="33.39333933393339%" id="mcps1.2.4.1.2"><p id="p199385118173"><a name="p199385118173"></a><a name="p199385118173"></a>API</p>
</th>
<th class="cellrowborder" valign="top" width="45.3945394539454%" id="mcps1.2.4.1.3"><p id="p18937511175"><a name="p18937511175"></a><a name="p18937511175"></a>Description</p>
</th>
</tr>
</thead>
<tbody><tr id="row159315151712"><td class="cellrowborder" rowspan="2" valign="top" width="21.21212121212121%" headers="mcps1.2.4.1.1 "><p id="p593135115176"><a name="p593135115176"></a><a name="p593135115176"></a>Read</p>
</td>
<td class="cellrowborder" valign="top" width="33.39333933393339%" headers="mcps1.2.4.1.2 "><p id="p1193651181714"><a name="p1193651181714"></a><a name="p1193651181714"></a>LOS_AtomicRead</p>
</td>
<td class="cellrowborder" valign="top" width="45.3945394539454%" headers="mcps1.2.4.1.3 "><p id="p09316512178"><a name="p09316512178"></a><a name="p09316512178"></a>Reads 32-bit atomic data.</p>
</td>
</tr>
<tr id="row1493151161719"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p119395111718"><a name="p119395111718"></a><a name="p119395111718"></a>LOS_Atomic64Read</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p49311514178"><a name="p49311514178"></a><a name="p49311514178"></a>Reads 64-bit atomic data.</p>
</td>
</tr>
<tr id="row69365111712"><td class="cellrowborder" rowspan="2" valign="top" width="21.21212121212121%" headers="mcps1.2.4.1.1 "><p id="p199355111175"><a name="p199355111175"></a><a name="p199355111175"></a>Write</p>
</td>
<td class="cellrowborder" valign="top" width="33.39333933393339%" headers="mcps1.2.4.1.2 "><p id="p1693175191714"><a name="p1693175191714"></a><a name="p1693175191714"></a>LOS_AtomicSet</p>
</td>
<td class="cellrowborder" valign="top" width="45.3945394539454%" headers="mcps1.2.4.1.3 "><p id="p129320516173"><a name="p129320516173"></a><a name="p129320516173"></a>Sets 32-bit atomic data.</p>
</td>
</tr>
<tr id="row1593651111718"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p7944510176"><a name="p7944510176"></a><a name="p7944510176"></a>LOS_Atomic64Set</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p294115191713"><a name="p294115191713"></a><a name="p294115191713"></a>Sets 64-bit atomic data.</p>
</td>
</tr>
<tr id="row149495114177"><td class="cellrowborder" rowspan="6" valign="top" width="21.21212121212121%" headers="mcps1.2.4.1.1 "><p id="p1394165151718"><a name="p1394165151718"></a><a name="p1394165151718"></a>Add</p>
</td>
<td class="cellrowborder" valign="top" width="33.39333933393339%" headers="mcps1.2.4.1.2 "><p id="p494115112179"><a name="p494115112179"></a><a name="p494115112179"></a>LOS_AtomicAdd</p>
</td>
<td class="cellrowborder" valign="top" width="45.3945394539454%" headers="mcps1.2.4.1.3 "><p id="p1694155120174"><a name="p1694155120174"></a><a name="p1694155120174"></a>Adds 32-bit atomic data.</p>
</td>
</tr>
<tr id="row394651101719"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p179435113171"><a name="p179435113171"></a><a name="p179435113171"></a>LOS_Atomic64Add</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p594851181718"><a name="p594851181718"></a><a name="p594851181718"></a>Adds 64-bit atomic data.</p>
</td>
</tr>
<tr id="row294185110171"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1834102212615"><a name="p1834102212615"></a><a name="p1834102212615"></a>LOS_AtomicInc</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p129413519173"><a name="p129413519173"></a><a name="p129413519173"></a>Adds 1 to 32-bit atomic data.</p>
</td>
</tr>
<tr id="row1894175101713"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1981302213264"><a name="p1981302213264"></a><a name="p1981302213264"></a>LOS_Atomic64Inc</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p167671640113316"><a name="p167671640113316"></a><a name="p167671640113316"></a>Adds 1 to 64-bit atomic data.</p>
</td>
</tr>
<tr id="row12946512178"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1994051181716"><a name="p1994051181716"></a><a name="p1994051181716"></a>LOS_AtomicIncRet</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p59414511172"><a name="p59414511172"></a><a name="p59414511172"></a>Adds 1 to 32-bit atomic data and returns the data.</p>
</td>
</tr>
<tr id="row1994551101712"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p129414519173"><a name="p129414519173"></a><a name="p129414519173"></a>LOS_Atomic64IncRet</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1194951111713"><a name="p1194951111713"></a><a name="p1194951111713"></a>Adds 1 to 64-bit atomic data and returns the data.</p>
</td>
</tr>
<tr id="row1794451121719"><td class="cellrowborder" rowspan="6" valign="top" width="21.21212121212121%" headers="mcps1.2.4.1.1 "><p id="p179412517173"><a name="p179412517173"></a><a name="p179412517173"></a>Subtract</p>
</td>
<td class="cellrowborder" valign="top" width="33.39333933393339%" headers="mcps1.2.4.1.2 "><p id="p89495115176"><a name="p89495115176"></a><a name="p89495115176"></a>LOS_AtomicSub</p>
</td>
<td class="cellrowborder" valign="top" width="45.3945394539454%" headers="mcps1.2.4.1.3 "><p id="p18220416345"><a name="p18220416345"></a><a name="p18220416345"></a>Performs subtraction on 32-bit atomic data.</p>
</td>
</tr>
<tr id="row139485131718"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1894195116176"><a name="p1894195116176"></a><a name="p1894195116176"></a>LOS_Atomic64Sub</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p20822124173415"><a name="p20822124173415"></a><a name="p20822124173415"></a>Performs subtraction on 64-bit atomic data.</p>
</td>
</tr>
<tr id="row209505110175"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p7951051141713"><a name="p7951051141713"></a><a name="p7951051141713"></a>LOS_AtomicDec</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p382234117340"><a name="p382234117340"></a><a name="p382234117340"></a>Subtracts 1 from 32-bit atomic data.</p>
</td>
</tr>
<tr id="row995151171711"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p395151131715"><a name="p395151131715"></a><a name="p395151131715"></a>LOS_Atomic64Dec</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1982244117340"><a name="p1982244117340"></a><a name="p1982244117340"></a>Subtracts 1 from 64-bit atomic data.</p>
</td>
</tr>
<tr id="row895155117179"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p395155151719"><a name="p395155151719"></a><a name="p395155151719"></a>LOS_AtomicDecRet</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p198222414349"><a name="p198222414349"></a><a name="p198222414349"></a>Subtracts 1 from 32-bit atomic data and returns the result.</p>
</td>
</tr>
<tr id="row59511518170"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1495125119175"><a name="p1495125119175"></a><a name="p1495125119175"></a>LOS_Atomic64DecRet</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p198221841103419"><a name="p198221841103419"></a><a name="p198221841103419"></a>Subtracts 1 from 64-bit atomic data and returns the result.</p>
</td>
</tr>
<tr id="row159575131714"><td class="cellrowborder" rowspan="4" valign="top" width="21.21212121212121%" headers="mcps1.2.4.1.1 "><p id="p159585110177"><a name="p159585110177"></a><a name="p159585110177"></a>Swap</p>
</td>
<td class="cellrowborder" valign="top" width="33.39333933393339%" headers="mcps1.2.4.1.2 "><p id="p29515114174"><a name="p29515114174"></a><a name="p29515114174"></a>LOS_AtomicXchgByte</p>
</td>
<td class="cellrowborder" valign="top" width="45.3945394539454%" headers="mcps1.2.4.1.3 "><p id="p6956510177"><a name="p6956510177"></a><a name="p6956510177"></a>Swaps 8-bit memory data.</p>
</td>
</tr>
<tr id="row14951451111710"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p8952514173"><a name="p8952514173"></a><a name="p8952514173"></a>LOS_AtomicXchg16bits</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p12334173143919"><a name="p12334173143919"></a><a name="p12334173143919"></a>Swaps 16-bit memory data.</p>
</td>
</tr>
<tr id="row595251131716"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1495145117171"><a name="p1495145117171"></a><a name="p1495145117171"></a>LOS_AtomicXchg32bits</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p9951513173"><a name="p9951513173"></a><a name="p9951513173"></a>Swaps 32-bit memory data.</p>
</td>
</tr>
<tr id="row195165131718"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p18951151141717"><a name="p18951151141717"></a><a name="p18951151141717"></a>LOS_AtomicXchg64bits</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p169685115172"><a name="p169685115172"></a><a name="p169685115172"></a>Swaps 64-bit memory data.</p>
</td>
</tr>
<tr id="row149616511175"><td class="cellrowborder" rowspan="4" valign="top" width="21.21212121212121%" headers="mcps1.2.4.1.1 "><p id="p49615120172"><a name="p49615120172"></a><a name="p49615120172"></a>Compare and swap</p>
</td>
<td class="cellrowborder" valign="top" width="33.39333933393339%" headers="mcps1.2.4.1.2 "><p id="p129605112171"><a name="p129605112171"></a><a name="p129605112171"></a>LOS_AtomicCmpXchgByte</p>
</td>
<td class="cellrowborder" valign="top" width="45.3945394539454%" headers="mcps1.2.4.1.3 "><p id="p6965510178"><a name="p6965510178"></a><a name="p6965510178"></a>Compares and swaps 8-bit memory data.</p>
</td>
</tr>
<tr id="row99605171713"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p109675131711"><a name="p109675131711"></a><a name="p109675131711"></a>LOS_AtomicCmpXchg16bits</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p17961951191719"><a name="p17961951191719"></a><a name="p17961951191719"></a>Compares and swaps 16-bit memory data.</p>
</td>
</tr>
<tr id="row169614513177"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p49645115172"><a name="p49645115172"></a><a name="p49645115172"></a>LOS_AtomicCmpXchg32bits</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p129611512175"><a name="p129611512175"></a><a name="p129611512175"></a>Compares and swaps 32-bit memory data.</p>
</td>
</tr>
<tr id="row696175110179"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p16961051161715"><a name="p16961051161715"></a><a name="p16961051161715"></a>LOS_AtomicCmpXchg64bits</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1296205118179"><a name="p1296205118179"></a><a name="p1296205118179"></a>Compares and swaps 64-bit memory data.</p>
</td>
</tr>
</tbody>
</table>
The following table describes the APIs available for the OpenHarmony LiteOS-A kernel atomic operation module.
**Table 1** APIs for atomic operations
| Category | API | Description |
| ------------ | ----------------------- | --------------------------- |
| Read | LOS_AtomicRead | Reads 32-bit atomic data. |
| Read | LOS_Atomic64Read | Reads 64-bit atomic data. |
| Write | LOS_AtomicSet | Sets 32-bit atomic data. |
| Write | LOS_Atomic64Set | Sets 64-bit atomic data. |
| Add | LOS_AtomicAdd | Adds 32-bit atomic data. |
| Add | LOS_Atomic64Add | Adds 64-bit atomic data. |
| Add | LOS_AtomicInc | Adds 1 to 32-bit atomic data. |
| Add | LOS_Atomic64Inc | Adds 1 to 64-bit atomic data. |
| Add | LOS_AtomicIncRet | Adds 1 to 32-bit atomic data and returns the data. |
| Add | LOS_Atomic64IncRet | Adds 1 to 64-bit atomic data and returns the data. |
| Subtract | LOS_AtomicSub | Performs subtraction on 32-bit atomic data. |
| Subtract | LOS_Atomic64Sub | Performs subtraction on 64-bit atomic data. |
| Subtract | LOS_AtomicDec | Subtracts 1 from 32-bit atomic data. |
| Subtract | LOS_Atomic64Dec | Subtracts 1 from 64-bit atomic data. |
| Subtract | LOS_AtomicDecRet | Subtracts 1 from 32-bit atomic data and returns the result. |
| Subtract | LOS_Atomic64DecRet | Subtracts 1 from 64-bit atomic data and returns the result. |
| Swap | LOS_AtomicXchgByte | Swaps 8-bit memory data. |
| Swap | LOS_AtomicXchg16bits | Swaps 16-bit memory data. |
| Swap | LOS_AtomicXchg32bits | Swaps 32-bit memory data. |
| Swap | LOS_AtomicXchg64bits | Swaps 64-bit memory data. |
| Compare and swap| LOS_AtomicCmpXchgByte | Compares and swaps 8-bit memory data. |
| Compare and swap| LOS_AtomicCmpXchg16bits | Compares and swaps 16-bit memory data.|
| Compare and swap| LOS_AtomicCmpXchg32bits | Compares and swaps 32-bit memory data.|
| Compare and swap| LOS_AtomicCmpXchg64bits | Compares and swaps 64-bit memory data.|
### How to Develop
When multiple tasks perform addition, subtraction, and swap operations on the same memory data, use atomic operations to ensure predictability of results.
>![](../public_sys-resources/icon-note.gif) **NOTE**<br/>
>Atomic operation APIs support only integer data.
> **NOTE**<br>
> Atomic operation APIs support only integers.
### Development Example<a name="section8538651511"></a>
### Development Example
Example Description
**Example Description**
Call the atomic operation APIs and observe the result.
1. Create two tasks.
- Task 1: Call **LOS\_AtomicInc** to add the global variables 100 times.
- Task 2: Call **LOS\_AtomicDec** to subtract the global variables 100 times.
1. Create two tasks.
- Task 1: Call **LOS_AtomicInc** to add a global variable 100 times.
- Task 2: Call **LOS_AtomicDec** to subtract a global variable 100 times.
2. After the subtasks are complete, print the values of the global variables in the main task.
2. After the subtasks are complete, print the values of the global variable in the main task.
**Sample Code**
The sample code is as follows:
```
#include "los_hwi.h"
#include "los_atomic.h"
......@@ -275,7 +157,7 @@ UINT32 Example_AtomicTaskEntry(VOID)
**Verification**
```
g_sum = 0
```
# Interrupt and Exception Handling
## Basic Concepts<a name="section439816296117"></a>
## Basic Concepts
An interrupt is a signal to the processor emitted by hardware or software indicating an event that needs immediate attention. An interrupt alerts the processor of a high-priority condition requiring interruption of the code being executed by the processor. In this way, the CPU does not need to spend a lot of time in waiting and querying the peripheral status, which effectively improves the real-time performance and execution efficiency of the system.
Exception handling involves a series of actions taken by the OS to respond to exceptions \(chip hardware faults\) that occurred during the OS running, for example, printing the call stack information of the current function, CPU information, and call stack information of tasks when the virtual memory page is missing.
OpenHarmony supports the following interrupt operations:
## Working Principles<a name="section2792838318"></a>
+ Initializing an interrupt.
+ Creating an interrupt.
+ Enabling or disabling interrupts.
+ Restoring the system status before interrupts are disabled.
+ Deleting an interrupt.
Peripherals can complete certain work without the intervention of the CPU. In some cases, however, the CPU needs to perform certain work for peripherals. With the interrupt mechanism, the CPU responds to the interrupt request from a peripheral only when required, and execute other tasks when the peripherals do not require the CPU. The interrupt controller receives the input of other peripheral interrupt pins and sends interrupt signals to the CPU. You can enable or disable the interrupt source and set the priority and trigger mode of the interrupt source by programming the interrupt controller. Common interrupt controllers include vector interrupt controllers \(VICs\) and general interrupt controllers \(GICs\). The ARM Cortex-A7 uses GICs. After receiving an interrupt signal sent by the interrupt controller, the CPU interrupts the current task to respond to the interrupt request.
Exception handling involves a series of actions taken by the OS to respond to exceptions (chip hardware faults) that occurred during the OS running, for example, printing the call stack information of the current function, CPU information, and call stack information of tasks when the virtual memory page is missing.
Exception handling interrupts the normal running process of the CPU to handle exceptions, such as, undefined instructions, an attempt to modify read-only data, and unaligned address access. When an exception occurs, the CPU suspends the current program, handles the exception, and then continues to execute the program interrupted by the exception.
## Working Principles
Peripherals can complete certain work without the intervention of the CPU. In some cases, however, the CPU needs to perform certain work for peripherals. With the interrupt mechanism, the CPU responds to the interrupt request from a peripheral only when required, and execute other tasks when the peripherals do not require the CPU.
The interrupt controller receives the input from the interrupt pins of other peripherals and sends interrupt signals to the CPU. You can enable or disable the interrupt source and set the priority and trigger mode of the interrupt source by programming the interrupt controller. Common interrupt controllers include vector interrupt controllers (VICs) and general interrupt controllers (GICs). The ARM Cortex-A7 uses GICs.
After receiving an interrupt signal sent by the interrupt controller, the CPU interrupts the current task to respond to the interrupt request.
An exception interrupts the normal running process of the CPU to handle exceptions, such as, undefined instructions, an attempt to modify read-only data, and unaligned address access. When an exception occurs, the CPU suspends the current program, handles the exception, and then continues to execute the program interrupted by the exception.
The following uses the ARMv7-a architecture as an example. The interrupt vector table is the entry for interrupt and exception handling. The interrupt vector table contains the entry function for each interrupt and exception handling.
**Figure 1** Interrupt vector table<a name="fig1552753243714"></a>
**Figure 1** Interrupt vector table
![](figures/interrupt-vector-table.png "interrupt-vector-table")
## Development Guidelines<a name="section15415165510110"></a>
### Available APIs<a name="section57441612024"></a>
Exception handling is an internal mechanism and does not provide external APIs. The following table describes APIs available for the interrupt module.
<a name="table11657113333110"></a>
<table><thead align="left"><tr id="row1170612337312"><th class="cellrowborder" valign="top" width="19.900000000000002%" id="mcps1.1.4.1.1"><p id="p4706133373112"><a name="p4706133373112"></a><a name="p4706133373112"></a><strong id="b7792162213202"><a name="b7792162213202"></a><a name="b7792162213202"></a>Function</strong></p>
</th>
<th class="cellrowborder" valign="top" width="18.43%" id="mcps1.1.4.1.2"><p id="p1070653343117"><a name="p1070653343117"></a><a name="p1070653343117"></a><strong id="b19958356201"><a name="b19958356201"></a><a name="b19958356201"></a>API</strong></p>
</th>
<th class="cellrowborder" valign="top" width="61.67%" id="mcps1.1.4.1.3"><p id="p370613330311"><a name="p370613330311"></a><a name="p370613330311"></a><strong id="b1551072610204"><a name="b1551072610204"></a><a name="b1551072610204"></a>Description</strong></p>
</th>
</tr>
</thead>
<tbody><tr id="row8706123317311"><td class="cellrowborder" rowspan="2" valign="top" width="19.900000000000002%" headers="mcps1.1.4.1.1 "><p id="p4706193319318"><a name="p4706193319318"></a><a name="p4706193319318"></a>Creating or deleting interrupts</p>
</td>
<td class="cellrowborder" valign="top" width="18.43%" headers="mcps1.1.4.1.2 "><p id="p170683310317"><a name="p170683310317"></a><a name="p170683310317"></a>LOS_HwiCreate</p>
</td>
<td class="cellrowborder" valign="top" width="61.67%" headers="mcps1.1.4.1.3 "><p id="p15706833163110"><a name="p15706833163110"></a><a name="p15706833163110"></a>Creates an interrupt and registers the interrupt ID, interrupt triggering mode, interrupt priority, and interrupt handler. When an interrupt is triggered, the interrupt handler will be called.</p>
</td>
</tr>
<tr id="row18706153318316"><td class="cellrowborder" valign="top" headers="mcps1.1.4.1.1 "><p id="p1870615332312"><a name="p1870615332312"></a><a name="p1870615332312"></a>LOS_HwiDelete</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.1.4.1.2 "><p id="p770616333313"><a name="p770616333313"></a><a name="p770616333313"></a>Deletes an interrupt.</p>
</td>
</tr>
<tr id="row1370633316316"><td class="cellrowborder" rowspan="3" valign="top" width="19.900000000000002%" headers="mcps1.1.4.1.1 "><p id="p970611333318"><a name="p970611333318"></a><a name="p970611333318"></a>Enabling and disabling all interrupts</p>
</td>
<td class="cellrowborder" valign="top" width="18.43%" headers="mcps1.1.4.1.2 "><p id="p147061033103117"><a name="p147061033103117"></a><a name="p147061033103117"></a>LOS_IntUnLock</p>
</td>
<td class="cellrowborder" valign="top" width="61.67%" headers="mcps1.1.4.1.3 "><p id="p93681327171713"><a name="p93681327171713"></a><a name="p93681327171713"></a>Enables all interrupts of the current processor.</p>
</td>
</tr>
<tr id="row1270603314312"><td class="cellrowborder" valign="top" headers="mcps1.1.4.1.1 "><p id="p1970623343114"><a name="p1970623343114"></a><a name="p1970623343114"></a>LOS_IntLock</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.1.4.1.2 "><p id="p1161283971712"><a name="p1161283971712"></a><a name="p1161283971712"></a>Disables all interrupts for the current processor.</p>
</td>
</tr>
<tr id="row8706233173113"><td class="cellrowborder" valign="top" headers="mcps1.1.4.1.1 "><p id="p1770620337313"><a name="p1770620337313"></a><a name="p1770620337313"></a>LOS_IntRestore</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.1.4.1.2 "><p id="p1470643323112"><a name="p1470643323112"></a><a name="p1470643323112"></a>Restores to the status before all interrupts are disabled by using <strong id="b354311504226"><a name="b354311504226"></a><a name="b354311504226"></a>LOS_IntLock</strong>.</p>
</td>
</tr>
<tr id="row870793320317"><td class="cellrowborder" valign="top" width="19.900000000000002%" headers="mcps1.1.4.1.1 "><p id="p1970763318316"><a name="p1970763318316"></a><a name="p1970763318316"></a>Obtaining the maximum number of interrupts supported</p>
</td>
<td class="cellrowborder" valign="top" width="18.43%" headers="mcps1.1.4.1.2 "><p id="p1707333123115"><a name="p1707333123115"></a><a name="p1707333123115"></a>LOS_GetSystemHwiMaximum</p>
</td>
<td class="cellrowborder" valign="top" width="61.67%" headers="mcps1.1.4.1.3 "><p id="p4707173323111"><a name="p4707173323111"></a><a name="p4707173323111"></a>Obtains the maximum number of interrupts supported by the system.</p>
</td>
</tr>
</tbody>
</table>
### How to Develop<a name="section64332181221"></a>
1. Call **LOS\_HwiCreate** to create an interrupt.
2. Call **LOS\_HwiDelete** to delete the specified interrupt. Use this API based on actual requirements.
### Development Example<a name="section204698276478"></a>
## Development Guidelines
### Available APIs
Exception handling is an internal mechanism and does not provide external APIs. The following tables describe the APIs available for the interrupt module.
##### Creating or Deleting an Interrupt
| API | Description |
|------------ | ----------------------------------------------------------- |
| LOS_HwiCreate | Creates an interrupt and registers the interrupt ID, triggering mode, priority, and interrupt handler. When the interrupt is triggered, the interrupt handler will be called.|
| LOS_HwiDelete | Deletes an interrupt based on the interrupt number. |
##### Enabling or Disabling Interrupts
| API | Description |
| -------------- | ------------------------------------------- |
| LOS_IntUnlock | Enables all interrupts for the current processor. |
| LOS_IntLock | Disables all interrupts for the current processor. |
| LOS_IntRestore | Restores the status in which the system was before **LOS_IntLock** is called.|
##### Obtaining Interrupt Information
| API | Description |
| ----------------------- | ------------------------ |
| LOS_GetSystemHwiMaximum | Obtains the maximum number of interrupts supported by the system.|
### How to Develop
1. Call **LOS_HwiCreate** to create an interrupt.
2. Call **LOS_HwiDelete** to delete the specified interrupt. Use this API based on actual requirements.
### Development Example
This example implements the following:
1. Create an interrupt.
2. Delete an interrupt.
The following sample code shows how to create and delete an interrupt. When the interrupt **HWI\_NUM\_TEST** is generated, the interrupt handler function will be called.
1. Create an interrupt.
```
2. Delete an interrupt.
The following sample code demostrates how to create and delete an interrupt, and call the interrupt handler when the specified interrupt **HWI_NUM_TEST** is triggered. You can add the test function of the sample code to **TestTaskEntry** in **kernel/liteos_a/testsuites/kernel/src/osTest.c** for testing.
The sample code is as follows:
```c
#include "los_hwi.h"
/* Interrupt handler function*/
STATIC VOID HwiUsrIrq(VOID)
{
printf("in the func HwiUsrIrq \n");
PRINTK("in the func HwiUsrIrq \n");
}
static UINT32 Example_Interrupt(VOID)
{
UINT32 ret;
HWI_HANDLE_T hwiNum = 7;
HWI_PRIOR_T hwiPrio = 3;
HWI_HANDLE_T hwiNum = 7; // The interrupt number is 7.
HWI_PRIOR_T hwiPrio = 3; // The interrupt priority is 3.
HWI_MODE_T mode = 0;
HWI_ARG_T arg = 0;
/* Create an interrupt.*/
/* Create an interrupt. */
ret = LOS_HwiCreate(hwiNum, hwiPrio, mode, (HWI_PROC_FUNC)HwiUsrIrq, (HwiIrqParam *)arg);
if(ret == LOS_OK){
printf("Hwi create success!\n");
if (ret == LOS_OK) {
PRINTK("Hwi create success!\n");
} else {
printf("Hwi create failed!\n");
PRINTK("Hwi create failed!\n");
return LOS_NOK;
}
/* Delay 50 ticks. When a hardware interrupt occurs, call the HwiUsrIrq function.*/
/* Delay 50 ticks. Call HwiUsrIrq when a hardware interrupt occurs. */
LOS_TaskDelay(50);
/* Delete an interrupt./
ret = LOS_HwiDelete(hwiNum, (HwiIrqParam *)arg);
if(ret == LOS_OK){
printf("Hwi delete success!\n");
/* Delete the interrupt. */
ret = LOS_HwiDelete(hwiNum, (HwiIrqParam *)arg);
if (ret == LOS_OK) {
PRINTK("Hwi delete success!\n");
} else {
printf("Hwi delete failed!\n");
PRINTK("Hwi delete failed!\n");
return LOS_NOK;
}
return LOS_OK;
}
```
### Verification<a name="section1466144215476"></a>
### Verification
The development is successful if the return result is as follows:
......@@ -134,4 +133,3 @@ The development is successful if the return result is as follows:
Hwi create success!
Hwi delete success!
```
# Scheduler
## Basic Concepts<a name="section123882355719"></a>
## Basic Concepts
The OpenHarmony LiteOS-A kernel uses the preemptive scheduling mechanism for tasks. The tasks with a higher priority are scheduled first, and the tasks with the same priority are scheduled using the time slice polling. The system runs based on the real-time timeline from the startup, which ensures good real-time performance of the scheduling algorithm.
The OpenHarmony scheduling algorithm is embedded with the tickless mechanism, which ensures lower power consumption and on-demand response to tick interrupts. This minimizes useless tick interrupt response time and further improves the real-time performance of the system.
The OpenHarmony process scheduling policy is **SCHED\_RR**, and the thread scheduling policy can be **SCHED\_RR** or **SCHED\_FIFO**.
OpenHarmony supports **SCHED_RR** (time slice round robin) for process scheduling and **SCHED_RR** and **SCHED_FIFO** (first in, first out) for thread scheduling .
Threads are the minimum scheduling units in the OpenHarmony.
Threads are the minimum scheduling units in OpenHarmony.
## Working Principles<a name="section143015396572"></a>
The OpenHarmony uses process priority queue and thread priority queue for scheduling. The process priority ranges from 0 to 31, and there are 32 process priority bucket queues. Each bucket queue corresponds to a thread priority bucket queue. The thread priority ranges from 0 to 31, and a thread priority bucket queue also has 32 priority queues.
## Working Principles
OpenHarmony uses process priority queue and thread priority queue for scheduling. The process priority ranges from 0 to 31, and there are 32 process priority bucket queues. Each bucket queue corresponds to a thread priority bucket queue. The thread priority ranges from 0 to 31, and a thread priority bucket queue also has 32 priority queues.
**Figure 1** Scheduling priority bucket queue
**Figure 1** Scheduling priority bucket queue<a name="fig124425991619"></a>
![](figures/scheduling-priority-bucket-queue.png "scheduling-priority-bucket-queue")
The OpenHarmony system starts scheduling after the kernel initialization is complete. The processes or threads created during running are added to the scheduling queues. The system selects the optimal thread for scheduling based on the priorities of the processes and threads and the time slice consumption of the threads. Once a thread is scheduled, it is deleted from the scheduling queue. If a thread is blocked during running, the thread is added to the corresponding blocking queue and triggers scheduling of another thread. If no thread in the scheduling queue can be scheduled, the system selects the thread of the KIdle process for scheduling.
**Figure 2** Scheduling process<a name="fig1163494931810"></a>
**Figure 2** Scheduling process
![](figures/scheduling-process.png "scheduling-process")
## Development Guidelines<a name="section10604192145816"></a>
### Available APIs<a name="section207985910582"></a>
<a name="table687929113814"></a>
<table><thead align="left"><tr id="row513082983812"><th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.1.4.1.1"><p id="p121309298384"><a name="p121309298384"></a><a name="p121309298384"></a><strong id="b1684811125913"><a name="b1684811125913"></a><a name="b1684811125913"></a>Function</strong></p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.1.4.1.2"><p id="p713082933817"><a name="p713082933817"></a><a name="p713082933817"></a>API</p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.1.4.1.3"><p id="p20130829123810"><a name="p20130829123810"></a><a name="p20130829123810"></a><strong id="b66639257454"><a name="b66639257454"></a><a name="b66639257454"></a>Description</strong></p>
</th>
</tr>
</thead>
<tbody><tr id="row713032973813"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.1 "><p id="p0130429133818"><a name="p0130429133818"></a><a name="p0130429133818"></a>System scheduling</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.2 "><p id="p71581556124414"><a name="p71581556124414"></a><a name="p71581556124414"></a>LOS_Schedule</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.3 "><p id="p181303297387"><a name="p181303297387"></a><a name="p181303297387"></a>Triggers system scheduling.</p>
</td>
</tr>
</tbody>
</table>
### How to Develop<a name="section1015110331584"></a>
>![](../public_sys-resources/icon-note.gif) **NOTE:**
>Scheduling cannot be triggered during the system initialization process.
## Development Guidelines
### Available APIs
| API| Description|
| -------- | -------- |
| LOS_Schedule | Triggers system scheduling.|
| LOS_GetTaskScheduler | Obtains the scheduling policy of a task.|
| LOS_SetTaskScheduler | Sets the scheduling policy for a task.|
| LOS_GetProcessScheduler | Obtains the scheduling policy of a process.|
| LOS_SetProcessScheduler | Sets scheduling parameters, including the priority and scheduling policy, for a process.|
### How to Develop
> **NOTE**
>
> Scheduling cannot be triggered during the system initialization process.
......@@ -3,85 +3,64 @@
## Basic Concepts
Time management provides all time-related services for applications based on the system clock. The system clock is generated by the interrupts triggered by the output pulse of a timer or counter. The system clock is generally defined as an integer or a long integer. The period of an output pulse is a "clock tick". The system clock is also called time scale or tick. The duration of a tick can be configured statically. People use second or millisecond as the time unit, while the operating system uses tick. When operations such as suspending a task or delaying a task are performed, the time management module converts time between ticks and seconds or milliseconds.
Time management is performed based on the system clock. It provides time-related services for applications. The system clock is generated by the interrupts triggered by the output pulse of a timer or counter. The system clock is generally defined as an integer or a long integer. The period of an output pulse is a "clock tick".
The system clock is also called time scale or tick. The duration of a tick can be configured statically. People use second or millisecond as the time unit, while the operating system uses tick. When operations such as suspending a task or delaying a task are performed, the time management module converts time between ticks and seconds or milliseconds.
The mapping between ticks and seconds can be configured.
- **Cycle**
- Cycle
Cycle is the minimum time unit in the system. The cycle duration is determined by the system clock frequency, that is, the number of cycles per second.
- Tick
Cycle is the minimum time unit in the system. The cycle duration is determined by the system clock frequency, that is, the number of cycles per second.
Tick is the basic time unit of the operating system and is determined by the number of ticks per second configured by the user.
The OpenHarmony time management module provides time conversion, statistics, and delay functions.
- **Tick**
Tick is the basic time unit of the operating system and is determined by the number of ticks per second configured by the user.
## Development Guidelines
Before you start, learn about the system time and the APIs for time management.
The OpenHarmony time management module provides time conversion, statistics, and delay functions to meet users' time requirements.
## Development Guidelines
### Available APIs
The time management module provides APIs to implement conversion between the system running time, ticks, and seconds/milliseconds.
The following table describes APIs for OpenHarmony LiteOS-A time management. For more details about the APIs, see the API reference.
### Available APIs
**Table 1** APIs for time management
| Category| API Description |
| -------- | ------------------------------------------------------------ |
| Time conversion| **LOS_MS2Tick**: converts milliseconds to ticks.<br>**LOS_Tick2MS**: converts ticks to milliseconds. |
| Time statistics| **LOS_TickCountGet**: obtains the number of current ticks.<br>**LOS_CyclePerTickGet**: obtains the number of cycles of each tick.|
The following table describes APIs available for the OpenHarmony LiteOS-A time management. For more details about the APIs, see the API reference.
**Table 1** APIs of the time management module
<a name="table1316220185211"></a>
<table><thead align="left"><tr id="row191622182021"><th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.1"><p id="p13162121815218"><a name="p13162121815218"></a><a name="p13162121815218"></a>Function</p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.2"><p id="p12162618623"><a name="p12162618623"></a><a name="p12162618623"></a>API</p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.3"><p id="p16162118427"><a name="p16162118427"></a><a name="p16162118427"></a>Description</p>
</th>
</tr>
</thead>
<tbody><tr id="row04981218910"><td class="cellrowborder" rowspan="2" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p6462616696"><a name="p6462616696"></a><a name="p6462616696"></a>Time conversion</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p164931214913"><a name="p164931214913"></a><a name="p164931214913"></a>LOS_MS2Tick</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p8504121996"><a name="p8504121996"></a><a name="p8504121996"></a>Converts milliseconds into ticks.</p>
</td>
</tr>
<tr id="row7162101814216"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p816311185217"><a name="p816311185217"></a><a name="p816311185217"></a>LOS_Tick2MS</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p161632181721"><a name="p161632181721"></a><a name="p161632181721"></a>Converts ticks into milliseconds.</p>
</td>
</tr>
<tr id="row1516317181227"><td class="cellrowborder" rowspan="2" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p1077619231696"><a name="p1077619231696"></a><a name="p1077619231696"></a>Time statistics</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p181638181921"><a name="p181638181921"></a><a name="p181638181921"></a>LOS_TickCountGet</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p615864811116"><a name="p615864811116"></a><a name="p615864811116"></a>Obtains the current number of ticks.</p>
</td>
</tr>
<tr id="row101631818620"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p71633181125"><a name="p71633181125"></a><a name="p71633181125"></a>LOS_CyclePerTickGet</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p151631718124"><a name="p151631718124"></a><a name="p151631718124"></a>Obtains the number of cycles per tick.</p>
</td>
</tr>
</tbody>
</table>
### How to Develop
1. Call APIs to convert time.
2. Call APIs to perform time statistics.
1. Call APIs to convert time.
2. Call APIs to perform time statistics.
> **NOTE**
>
> - The system tick count can be obtained only after the system clock is enabled.
>
> - The time management module depends on **OS_SYS_CLOCK** and **LOSCFG_BASE_CORE_TICK_PER_SECOND** in **los_config.h**.
>
> - The number of system ticks is not counted when the interrupt feature is disabled. Therefore, the number of ticks cannot be used as the accurate time.
>![](public_sys-resources/icon-note.gif) **NOTE**<br/>
>- The system tick count can be obtained only after the system clock is enabled.
>- The time management module depends on **OS\_SYS\_CLOCK** and **LOSCFG\_BASE\_CORE\_TICK\_PER\_SECOND** in **los\_config.h**.
>- The number of system ticks is not counted when the interrupt feature is disabled. Therefore, the number of ticks cannot be used as the accurate time.
### Development Example
**Prerequisites**<br>
**Prerequisites**
The following parameters are configured:
- **LOSCFG\_BASE\_CORE\_TICK\_PER\_SECOND**: number of ticks per second in the system. The value range is (0, 1000].
- **OS\_SYS\_CLOCK**: system clock, in Hz.
- **LOSCFG_BASE_CORE_TICK_PER_SECOND**: number of ticks/second. The value range is (0, 1000).
- **OS_SYS_CLOCK**: system clock, in Hz.
**Sample Code**
......@@ -92,15 +71,16 @@ VOID Example_TransformTime(VOID)
{
UINT32 uwMs;
UINT32 uwTick;
uwTick = LOS_MS2Tick(10000);// Convert 10000 ms into ticks.
uwTick = LOS_MS2Tick(10000); // Convert 10000 ms to ticks.
PRINTK("uwTick = %d \n",uwTick);
uwMs= LOS_Tick2MS(100); // Convert 100 ticks into ms.
uwMs= LOS_Tick2MS(100); // Convert 100 ticks to ms.
PRINTK("uwMs = %d \n",uwMs);
}
```
Time statistics and delay:
```
VOID Example_GetTime(VOID)
{
......@@ -133,6 +113,7 @@ The result is as follows:
Time conversion:
```
uwTick = 10000
uwMs = 100
......@@ -140,9 +121,9 @@ uwMs = 100
Time statistics and delay:
```
LOS_CyclePerTickGet = 49500
LOS_TickCountGet = 5042
LOS_TickCountGet after delay = 5242
LOS_TickCountGet = 347931
LOS_TickCountGet after delay = 348134
```
# Virtual Dynamic Shared Object
## Basic Concepts<a name="section174577181688"></a>
Different from a common dynamic shared library, which stores its .so files in the file system, the virtual dynamic shared object \(VDSO\) has its .so files stored in the system image. The kernel determines the .so files needed and provides them to the application program. That is why the VDSO is called a virtual dynamic shared library.
## Basic Concepts
The VDSO mechanism allows OpenHarmony user-mode programs to quickly obtain kernel-related data. It can accelerate certain system calls and implement quick read of non-sensitive data \(hardware and software configuration\).
Different from a common dynamic shared library, which stores its .so files in the file system, the virtual dynamic shared object (VDSO) has its .so files stored in the system image. The kernel determines the .so files needed and provides them to the application program. That is why the VDSO is called a virtual dynamic shared library.
## Working Principles<a name="section546363114810"></a>
The VDSO mechanism allows OpenHarmony user-mode programs to quickly obtain kernel-related data. It can accelerate certain system calls and implement quick read of non-sensitive data (hardware and software configuration).
The VDSO can be regarded as a section of memory \(read-only\) maintained by the kernel and mapped to the address space of the user-mode applications. By linking **vdso.so**, the applications can directly access this mapped memory instead of invoking system calls, accelerating application execution.
## Working Principles
The VDSO can be regarded as a section of memory (read-only) maintained by the kernel and mapped to the address space of the user-mode applications. By linking **vdso.so**, the applications can directly access this mapped memory instead of invoking system calls, accelerating application execution.
VDSO can be divided into:
- Data page: provides the kernel-time data mapped to the user process.
- Code page: provides the logic for shielding system calls.
- Data page: provides the kernel-time data mapped to the user process.
- Code page: provides the logic for shielding system calls.
**Figure 1** VDSO system design
**Figure 1** VDSO system design<a name="fig1986131094711"></a>
![](figures/vdso-system-design.jpg "vdso-system-design")
The VDSO mechanism involves the following steps:
......@@ -30,7 +33,7 @@ The VDSO mechanism involves the following steps:
5. Binds the VDSO symbols when the user program creates dynamic linking.
6. The VDSO code page intercepts specific system calls \(for example, **clock\_gettime\(CLOCK\_REALTIME\_COARSE, &ts\)**\).
6. The VDSO code page intercepts specific system calls (for example, **clock_gettime(CLOCK_REALTIME_COARSE, &amp;ts)**).
7. The VDSO code page allows direct read of the mapped VDSO data page rather than invoking a system call.
......@@ -38,7 +41,10 @@ The VDSO mechanism involves the following steps:
9. Returns the data obtained from the VDSO data page to the user program.
>![](../public_sys-resources/icon-note.gif) **NOTE:**
>- The VDSO mechanism supports the **CLOCK\_REALTIME\_COARSE** and **CLOCK\_MONOTONIC\_COARSE** functions of the **clock\_gettime** API in the LibC library. For details about how to use the **clock\_gettime** API, see the POSIX standard. You can call **clock\_gettime\(CLOCK\_REALTIME\_COARSE, &ts\)** or **clock\_gettime\(CLOCK\_MONOTONIC\_COARSE, &ts\)** of the LibC library to use the VDSO.
>- When VDSO is used, the time precision is the same as that of the tick interrupt of the system. The VDSO mechanism is applicable to the scenario where there is no demand for high time precision and **clock\_gettime** or **gettimeofday** is frequently triggered in a short period of time. The VDSO mechanism is not recommended for the system demanding high time precision.
> **NOTE**<br>
>
> - The VDSO mechanism supports the **CLOCK_REALTIME_COARSE** and **CLOCK_MONOTONIC_COARSE** functions of the **clock_gettime** API in the LibC library. For details about how to use the **clock_gettime** API, see the POSIX standard.
>
> - You can call **clock_gettime(CLOCK_REALTIME_COARSE, &amp;ts)** or **clock_gettime(CLOCK_MONOTONIC_COARSE, &amp;ts)** of the Libc library to use the VDSO.
>
> - When VDSO is used, the time precision is the same as that of the tick interrupt of the system. The VDSO mechanism is applicable to the scenario where there is no demand for high time precision and **clock_gettime** or **gettimeofday** is frequently triggered in a short period of time. The VDSO mechanism is not recommended for the system demanding high time precision.
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册