鴻蒙輕內(nèi)核M核源碼分析系列之Musl LibC
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
LiteOS-M內(nèi)核LibC實現(xiàn)有2種,可以根據(jù)需求進行二選一,分別是musl libC和newlibc。本文先學(xué)習(xí)下Musl LibC的實現(xiàn)代碼。文中所涉及的源碼,均可以在開源站點https://gitee.com/openharmony/kernel_liteos_m 獲取。LiteOS-M內(nèi)核提供了和內(nèi)核相關(guān)的文件系統(tǒng)、內(nèi)存申請釋放接口,其他接口可以直接使用Musl提供的。我們分別來看下內(nèi)核提供的接口部分。
1、Musl LibC文件系統(tǒng)
在使用Musl LibC并且使能支持POSIX FS API時,可以使用文件kal\libc\musl\fs.c中定義的文件系統(tǒng)操作接口。這些是標(biāo)準(zhǔn)的POSIX接口,如果想了解其用法,可以參考Section 2: system calls??梢栽诰W(wǎng)頁上搜索,也可以直接把上述網(wǎng)址和函數(shù)名稱進行拼接,如對于mount()函數(shù),可以直接訪問https://linux.die.net/man/2/mount。opendir等部分函數(shù)需要在Section 3: library functions網(wǎng)頁上查看。下文快速記錄下各個函數(shù)的使用方法。
1.1 函數(shù)mount
函數(shù)mount會掛載source參數(shù)(通常是設(shè)備名稱,也可以是目錄)指定的文件系統(tǒng)到target參數(shù)指定的目錄。文件系統(tǒng)類型LiteOS-M內(nèi)核支持"fat"和"littlefs"兩種類型。"littlefs"文件系統(tǒng)不需要掛載選項參數(shù)mountflags。對于fat文件類型,掛載選項參數(shù)定義在文件third_party\musl\porting\liteos_m\kernel\include\sys\mount.h中,如MS_RDONLY、MS_NOSUID、MS_REMOUNT等等。參數(shù)data由文件系統(tǒng)進行解析,fat文件類型不需要該參數(shù);"littlefs"文件系統(tǒng)需要傳入的data參數(shù)應(yīng)該為 (struct lfs_config*)指針類型。
該函數(shù)會調(diào)用components\fs\vfs\los_fs.c中的函數(shù)LOS_FsMount,后文會專門講解FS VFS。
- int mount(const char *source, const char *target,
- const char *filesystemtype, unsigned long mountflags,
- const void *data)
- {
- return LOS_FsMount(source, target, filesystemtype, mountflags, data);
- }
1.2 函數(shù)umount和umount2
函數(shù)umount, umount2用于unmount卸載文件系統(tǒng)。參數(shù)target指定要卸載的文件系統(tǒng)。函數(shù)umount2除了卸載,還可以指定flag參數(shù)來控制卸載行為。支持的參數(shù)定義在third_party\musl\porting\liteos_m\kernel\include\sys\mount.h,如MNT_FORCE、MNT_DETACH、MNT_EXPIRE和UMOUNT_NOFOLLOW。
- int umount(const char *target)
- {
- return LOS_FsUmount(target);
- }
- int umount2(const char *target, int flag)
- {
- return LOS_FsUmount2(target, flag);
- }
1.3 函數(shù)open、close和unlink
函數(shù)open用于打開一個文件或設(shè)備,可能會先創(chuàng)建文件或設(shè)備。參數(shù)path指定文件或設(shè)備的路徑,參數(shù)oflag需要使用下面的訪問模式O_RDONLY, O_WRONLY, O_RDWR中的一個,這幾個定義在文件third_party\musl\porting\liteos_m\kernel\include\fcntl.h。third_party\musl\porting\liteos_m\kernel\include\bits\fcntl.h。另外,還有些其他文件創(chuàng)建標(biāo)簽或文件狀態(tài)標(biāo)簽可以通過邏輯與進行指定。文件創(chuàng)建標(biāo)簽有O_CLOEXEC, O_CREAT, O_DIRECTORY, O_EXCL, O_NOCTTY, O_NOFOLLOW, O_TRUNC和O_TTY_INIT。其余的為文件狀態(tài)標(biāo)簽,這些標(biāo)簽定義文件中third_party\musl\porting\liteos_m\kernel\include\bits\fcntl.h中。可以訪問https://linux.die.net/man/2/open了解這些標(biāo)簽的詳細(xì)用法。
函數(shù)open返回值為文件描述符file descriptor,會被其他函數(shù)如read, write, lseek, fcntl等使用。函數(shù)close用于關(guān)閉一個文件描述符,使fd不再引用任何文件,可被再次重用。函數(shù)unlink用于刪除path路徑指定的文件。
- int open(const char *path, int oflag, ...)
- {
- va_list vaList;
- va_start(vaList, oflag);
- int ret;
- ret = LOS_Open(path, oflag, vaList);
- va_end(vaList);
- return ret;
- }
- int close(int fd)
- {
- return LOS_Close(fd);
- }
- int unlink(const char *path)
- {
- return LOS_Unlink(path);
- }
1.4 函數(shù)read和write
函數(shù)read嘗試從fd中讀取nbyte字節(jié)的數(shù)據(jù)到buf開始的緩存里,讀取成功時返回讀取的字節(jié)數(shù)目。函數(shù)write把buf處開始的nbyte字節(jié)數(shù)據(jù)寫入fd引用的文件里,寫入成功時返回實際寫入的字節(jié)數(shù)目。
- ssize_t read(int fd, void *buf, size_t nbyte)
- {
- return LOS_Read(fd, buf, nbyte);
- }
- ssize_t write(int fd, const void *buf, size_t nbyte)
- {
- return LOS_Write(fd, buf, nbyte);
- }
1.5 函數(shù)lseek
函數(shù)lseek用于重新定位文件讀寫的偏移位置。參數(shù)whence取值為SEEK_SET、SEEK_CUR或SEEK_END,定義在文件third_party\musl\porting\liteos_m\kernel\include\fcntl.h。
- SEEK_SET
偏移設(shè)置在offset字節(jié)處。
- SEEK_CUR
偏移設(shè)置在當(dāng)前位置加上offset字節(jié)處。
- SEEK_END
偏移設(shè)置在文件大小加上offset字節(jié)處。
函數(shù)執(zhí)行成功時,返回值為從文件開頭的偏移字節(jié)數(shù)值。
- off_t lseek(int fd, off_t offset, int whence)
- {
- return LOS_Lseek(fd, offset, whence);
- }}
1.6 函數(shù)fstat、stat和statfs
函數(shù)fstat和stat用于獲取文件的狀態(tài)state,參數(shù)參數(shù)分別是文件描述符和文件路徑。參數(shù)中的struct stat結(jié)構(gòu)體定義在文件third_party\musl\porting\liteos_m\kernel\include\bits\stat.h中。
函數(shù)statfs返回文件系統(tǒng)統(tǒng)計statistics數(shù)據(jù),結(jié)構(gòu)體struct statfs定義在文件third_party\musl\porting\liteos_m\kernel\include\bits\statfs.h中。
- int fstat(int fd, struct stat *buf)
- {
- return LOS_Fstat(fd, buf);
- }
- int stat(const char *path, struct stat *buf)
- {
- return LOS_Stat(path, buf);
- }
- int statfs(const char *path, struct statfs *buf)
- {
- return LOS_Statfs(path, buf);
- }
1.7 函數(shù)mkdir、opendir、readir、closedir和rmdrir
函數(shù)mkdir用于創(chuàng)建一個目錄,目錄名稱由參數(shù)path指定。參數(shù)mode指定目錄權(quán)限。創(chuàng)建成功返回0,否則返回-1。
函數(shù)opendir用于打開一個目錄流a directory stream,目錄名稱由參數(shù)dirName指定,返回一個執(zhí)行目錄劉的指針。發(fā)生錯誤時,返回NULL,并設(shè)置errno。返回值類型DIR是struct __dirstream的別名,定義在文件中third_party\musl\porting\liteos_m\kernel\include\dirent.h??梢栽L問https://linux.die.net/man/3/opendir了解更多關(guān)于該函數(shù)的信息。
函數(shù)readdir用于讀取一個目錄,返回一個struct dirent結(jié)構(gòu)體指針,代表目錄流DIR *dir中的下一個目錄條目directory entry。到達目錄流尾部或錯誤時,返回NULL。結(jié)構(gòu)體定義在文件third_party\musl\porting\liteos_m\kernel\include\bits\dirent.h中。 可以訪問https://linux.die.net/man/3/readdir了解更多關(guān)于該函數(shù)的信息。
函數(shù)closedir用于關(guān)閉一個目錄。函數(shù)rmdir用于刪除一個目錄,只有空目錄才會被刪除。
- int mkdir(const char *path, mode_t mode)
- {
- return LOS_Mkdir(path, mode);
- }
- DIR *opendir(const char *dirName)
- {
- return LOS_Opendir(dirName);
- }
- struct dirent *readdir(DIR *dir)
- {
- return LOS_Readdir(dir);
- }
- int closedir(DIR *dir)
- {
- return LOS_Closedir(dir);
- }
- int rmdir(const char *path)
- {
- return LOS_Unlink(path);
- }
1.8 函數(shù)fsync
函數(shù)mkdir用于同步內(nèi)存中所有已修改的文件數(shù)據(jù)到儲存設(shè)備。可以訪問https://linux.die.net/man/3/fsync了解更多關(guān)于該函數(shù)的信息。
- int fsync(int fd)
- {
- return LOS_Fsync(fd);
- }
1.9 函數(shù)rename
函數(shù)rename用于重命名一個文件??梢栽L問https://linux.die.net/man/3/rename了解更多關(guān)于該函數(shù)的信息。
- int rename(const char *oldName, const char *newName)
- {
- return LOS_Rename(oldName, newName);
- }
1.10 函數(shù)ftruncate
函數(shù)ftruncate用于截斷一個文件到指定的長度??梢栽L問https://linux.die.net/man/3/ftruncate了解更多關(guān)于該函數(shù)的信息。
- int ftruncate(int fd, off_t length)
- {
- return LOS_Ftruncate(fd, length);
- }
2、Musl LibC內(nèi)存分配釋放
LiteOS-M內(nèi)核提供了內(nèi)存分配釋放函數(shù)。這些是標(biāo)準(zhǔn)的POSIX接口,如果想了解其用法,可以參考Section 3: library functions??梢栽诰W(wǎng)頁上搜索,也可以直接把上述網(wǎng)址和函數(shù)名稱進行拼接,如對于malloc()函數(shù),可以直接訪問https://linux.die.net/man/3/malloc。opendir等部分函數(shù)需要在網(wǎng)頁上查看。下文快速記錄下各個函數(shù)的使用方法。
1.1 函數(shù)malloc、free和memalign
函數(shù)malloc和free分別調(diào)用內(nèi)核內(nèi)存模塊的接口來實現(xiàn)內(nèi)存申請和釋放。函數(shù)memalign可以以指定的內(nèi)存對齊大小來申請內(nèi)存。
- void free(void *ptr)
- {
- if (ptr == NULL) {
- return;
- }
- LOS_MemFree(OS_SYS_MEM_ADDR, ptr);
- }
- void *malloc(size_t size)
- {
- if (size == 0) {
- return NULL;
- }
- return LOS_MemAlloc(OS_SYS_MEM_ADDR, size);
- }
- void *memalign(size_t boundary, size_t size)
- {
- if (size == 0) {
- return NULL;
- }
- return LOS_MemAllocAlign(OS_SYS_MEM_ADDR, size, boundary);
- }
1.2 函數(shù)malloc、free和memalign
函數(shù)calloc在內(nèi)存的動態(tài)存儲區(qū)中分配nitems個長度為size的連續(xù)空間,函數(shù)返回一個指向分配起始地址的指針;如果分配不成功,返回NULL。
函數(shù)zalloc和malloc的區(qū)別是,申請成功后,對申請的內(nèi)存區(qū)域置0。函數(shù)realloc用于重新申請一塊內(nèi)存區(qū)域。
- void *calloc(size_t nitems, size_t size)
- {
- size_t real_size;
- void *ptr = NULL;
- if (nitems == 0 || size == 0) {
- return NULL;
- }
- real_size = (size_t)(nitems * size);
- ptr = LOS_MemAlloc(OS_SYS_MEM_ADDR, real_size);
- if (ptr != NULL) {
- (void)memset_s(ptr, real_size, 0, real_size);
- }
- return ptr;
- }
- void *zalloc(size_t size)
- {
- void *ptr = NULL;
- if (size == 0) {
- return NULL;
- }
- ptr = LOS_MemAlloc(OS_SYS_MEM_ADDR, size);
- if (ptr != NULL) {
- (void)memset_s(ptr, size, 0, size);
- }
- return ptr;
- }
- void *realloc(void *ptr, size_t size)
- {
- if (ptr == NULL) {
- return malloc(size);
- }
- if (size == 0) {
- free(ptr);
- return NULL;
- }
- return LOS_MemRealloc(OS_SYS_MEM_ADDR, ptr, size);
- }
小結(jié)
本文學(xué)習(xí)了LiteOS-M內(nèi)核Musl LibC的實現(xiàn),特別是文件系統(tǒng)和內(nèi)存分配釋放部分。
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)