• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Standard Library
2
3
4The 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.
5
6
7## Standard Library API Framework
8
9**Figure 1** POSIX framework
10
11![](figures/posix-framework.png "posix-framework")
12
13The musl libc library supports POSIX standards. The OpenHarmony kernel adapts the related system call APIs to implement external functions.
14
15For 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.
16
17
18### Development Example
19
20
21####  Example Description
22
23In 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.
24
25####  Sample Code
26
27The sample code can be compiled and verified in **./kernel/liteos_a/testsuites/kernel/src/osTest.c**. The **ExamplePosix** function is called in **TestTaskEntry**.
28
29The sample code is as follows:
30
31```
32#include <stdio.h>
33#include <unistd.h>
34#include <pthread.h>
35
36#define THREAD_NUM 3
37int g_startNum = 0; /* Number of threads to start */
38int g_wakenNum = 0; /* Number of threads to wake up */
39
40struct testdata {
41    pthread_mutex_t mutex;
42    pthread_cond_t cond;
43} g_td;
44
45/* Entry function of the child thread */
46static VOID *ChildThreadFunc(VOID *arg)
47{
48    int rc;
49    pthread_t self = pthread_self();
50
51    /* Acquire a mutex. */
52    rc = pthread_mutex_lock(&g_td.mutex);
53    if (rc != 0) {
54        dprintf("ERROR:take mutex lock failed, error code is %d!\n", rc);
55        goto EXIT;
56    }
57
58    /* The value of g_startNum is increased by 1. The value indicates the number of child threads that have acquired a mutex. */
59    g_startNum++;
60
61     /* Wait for the cond variable. */
62    rc = pthread_cond_wait(&g_td.cond, &g_td.mutex);
63    if (rc != 0) {
64        dprintf("ERROR: pthread condition wait failed, error code is %d!\n", rc);
65        (void)pthread_mutex_unlock(&g_td.mutex);
66        goto EXIT;
67    }
68
69    /* Attempt to acquire a mutex, which is failed in normal cases. */
70    rc = pthread_mutex_trylock(&g_td.mutex);
71    if (rc == 0) {
72        dprintf("ERROR: mutex gets an abnormal lock!\n");
73        goto EXIT;
74    }
75
76    /* 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. */
77    g_wakenNum++;
78
79    /* Release a mutex. */
80    rc = pthread_mutex_unlock(&g_td.mutex);
81    if (rc != 0) {
82        dprintf("ERROR: mutex release failed, error code is %d!\n", rc);
83        goto EXIT;
84    }
85EXIT:
86    return NULL;
87}
88
89static int ExamplePosix(VOID)
90{
91    int i, rc;
92    pthread_t thread[THREAD_NUM];
93
94    /* Initialize the mutex. */
95    rc = pthread_mutex_init(&g_td.mutex, NULL);
96    if (rc != 0) {
97        dprintf("ERROR: mutex init failed, error code is %d!\n", rc);
98        goto ERROROUT;
99    }
100
101    /* Initialize the cond variable. */
102    rc = pthread_cond_init(&g_td.cond, NULL);
103    if (rc != 0) {
104        dprintf("ERROR: pthread condition init failed, error code is %d!\n", rc);
105        goto ERROROUT;
106    }
107
108    /* Create child threads in batches. */
109    for (i = 0; i < THREAD_NUM; i++) {
110        rc = pthread_create(&thread[i], NULL, ChildThreadFunc, NULL);
111        if (rc != 0) {
112            dprintf("ERROR: pthread create failed, error code is %d!\n", rc);
113            goto ERROROUT;
114        }
115    }
116    dprintf("pthread_create ok\n");
117
118    /* Wait until all child threads obtain a mutex. */
119    while (g_startNum < THREAD_NUM) {
120        usleep(100);
121    }
122
123    /* Acquire a mutex and block all threads using pthread_cond_wait. */
124    rc = pthread_mutex_lock(&g_td.mutex);
125    if (rc != 0) {
126        dprintf("ERROR: mutex lock failed, error code is %d\n", rc);
127        goto ERROROUT;
128    }
129
130    /* Release the mutex. */
131    rc = pthread_mutex_unlock(&g_td.mutex);
132    if (rc != 0) {
133        dprintf("ERROR: mutex unlock failed, error code is %d!\n", rc);
134        goto ERROROUT;
135    }
136
137    for (int j = 0; j < THREAD_NUM; j++) {
138        /* Broadcast signals on the cond variable. */
139        rc = pthread_cond_signal(&g_td.cond);
140        if (rc != 0) {
141            dprintf("ERROR: pthread condition failed, error code is %d!\n", rc);
142            goto ERROROUT;
143        }
144    }
145
146    sleep(1);
147
148    /* Check whether all child threads are woken up. */
149    if (g_wakenNum != THREAD_NUM) {
150        dprintf("ERROR: not all threads awaken, only %d thread(s) awaken!\n", g_wakenNum);
151        goto ERROROUT;
152    }
153    dprintf("all threads awaked\n");
154
155    /* Join all  child threads, that is, wait for the end of all  child threads. */
156    for (i = 0; i < THREAD_NUM; i++) {
157        rc = pthread_join(thread[i], NULL);
158        if (rc != 0) {
159            dprintf("ERROR: pthread join failed, error code is %d!\n", rc);
160            goto ERROROUT;
161        }
162    }
163    dprintf("all threads join ok\n");
164
165    /* Destroy the cond variable. */
166    rc = pthread_cond_destroy(&g_td.cond);
167    if (rc != 0) {
168        dprintf("ERROR: pthread condition destroy failed, error code is %d!\n", rc);
169        goto ERROROUT;
170    }
171    return 0;
172ERROROUT:
173    return -1;
174}
175```
176
177#### Verification
178
179  The output is as follows:
180
181```
182pthread_create ok
183all threads awaked
184all threads join ok
185```
186
187## Differences from the Linux Standard Library
188
189The 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.
190
191
192### Process
193
194- The OpenHarmony user-mode processes support only static priorities, which range from 10 (highest) to 31 (lowest).
195
196- The OpenHarmony user-mode threads support only static priorities, which range from 0 (highest) to 31 (lowest).
197
198- The OpenHarmony process scheduling supports **SCHED_RR** only, and thread scheduling supports **SCHED_RR** or **SCHED_FIFO**.
199
200
201### Memory
202
203**Differences from Linux mmap**
204
205mmap prototype: **void \*mmap (void \*addr, size_t length, int prot, int flags, int fd, off_t offset)**
206
207The 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.
208
209**Example**
210
211
212Linux:
213
214```
215int main(int argc, char *argv[])
216{
217    int fd;
218    void *addr = NULL;
219    ...
220    fd = open(argv[1], O_RDONLY);
221    if (fd == -1){
222        perror("open");
223        exit(EXIT_FAILURE);
224    }
225    addr = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, offset);
226    if (addr == MAP_FAILED) {
227        perror("mmap");
228        exit(EXIT_FAILURE);
229    }
230    close(fd);  /* OpenHarmony does not support closing fd immediately after the mapping is successful. */
231    ...
232    exit(EXIT_SUCCESS);
233}
234```
235
236
237  OpenHarmony:
238
239```
240int main(int argc, char *argv[])
241{
242    int fd;
243    void *addr = NULL;
244    ...
245    fd = open(argv[1], O_RDONLY);
246    if (fd == -1) {
247        perror("open");
248        exit(EXIT_FAILURE);
249    }
250    addr = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, offset);
251    if (addr == MAP_FAILED) {
252        perror("mmap");
253        exit(EXIT_FAILURE);
254    }
255    ...
256    munmap(addr, length);
257    close(fd);  /* Close fd after the munmap is canceled. */
258    exit(EXIT_SUCCESS);
259}
260```
261
262
263### File System
264
265System directories: You cannot modify system directories and device mount directories, which include **/dev**, **/proc**, **/app**, **/bin**, **/data**, **/etc**, **/lib**, **/system**, and **/usr**.
266
267User 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.
268
269Except 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.
270
271
272### Signal
273
274- The default behavior for signals does not include **STOP**, **CONTINUE**, or **COREDUMP**.
275
276- 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.
277
278- After a process exits, **SIGCHLD** is sent to the parent process. The sending action cannot be canceled.
279
280- Only signals 1 to 30 are supported. The callback is invoked only once even if the same signal is received multiple times.
281
282
283### Time
284
285The 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.
286