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