摘要:本文學習了LiteOS-M核心Musl LibC的實現,特別是檔案系統和記憶體分配釋放部分。
本文分享自華為雲社群《鴻蒙輕核心M核原始碼分析系列十九 Musl LibC》,作者:zhushy。
LiteOS-M核心LibC實現有2種,可以根據需求進行二選一,分別是musl libC和newlibc。本文先學習下Musl LibC的實現程式碼。文中所涉及的原始碼,均可以在開源站點https://gitee.com/openharmony/kernel_liteos_m 獲取。LiteOS-M核心提供了和核心相關的檔案系統、記憶體申請釋放介面,其他介面可以直接使用Musl提供的。我們分別來看下核心提供的介面部分。
1、Musl LibC檔案系統
在使用Musl LibC並且使能支援POSIX FS API時,可以使用檔案kal\libc\musl\fs.c中定義的檔案系統操作介面。這些是標準的POSIX介面,如果想了解其用法,可以參考Section 2: system calls。可以在網頁上搜尋,也可以直接把上述網址和函式名稱進行拼接,如對於mount()函式,可以直接訪問https://linux.die.net/man/2/mount。opendir等部分函式需要在Section 3: library functions網頁上檢視。下文快速記錄下各個函式的使用方法。
1.1 函式mount
函式mount會掛載source引數(通常是裝置名稱,也可以是目錄)指定的檔案系統到target引數指定的目錄。檔案系統型別LiteOS-M核心支援"fat"和"littlefs"兩種型別。"littlefs"檔案系統不需要掛載選項引數mountflags。對於fat檔案型別,掛載選項引數定義在檔案third_party\musl\porting\liteos_m\kernel\include\sys\mount.h中,如MS_RDONLY、MS_NOSUID、MS_REMOUNT等等。引數data由檔案系統進行解析,fat檔案型別不需要該引數;"littlefs"檔案系統需要傳入的data引數應該為 (struct lfs_config*)指標型別。
該函式會呼叫components\fs\vfs\los_fs.c中的函式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 函式umount和umount2
函式umount, umount2用於unmount解除安裝檔案系統。引數target指定要解除安裝的檔案系統。函式umount2除了解除安裝,還可以指定flag引數來控制解除安裝行為。支援的引數定義在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 函式open、close和unlink
函式open用於開啟一個檔案或裝置,可能會先建立檔案或裝置。引數path指定檔案或裝置的路徑,引數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。另外,還有些其他檔案建立標籤或檔案狀態標籤可以通過邏輯與進行指定。檔案建立標籤有O_CLOEXEC, O_CREAT, O_DIRECTORY, O_EXCL, O_NOCTTY, O_NOFOLLOW, O_TRUNC和O_TTY_INIT。其餘的為檔案狀態標籤,這些標籤定義檔案中third_party\musl\porting\liteos_m\kernel\include\bits\fcntl.h中。可以訪問https://linux.die.net/man/2/open瞭解這些標籤的詳細用法。
函式open返回值為檔案描述符file descriptor,會被其他函式如read, write, lseek, fcntl等使用。函式close用於關閉一個檔案描述符,使fd不再引用任何檔案,可被再次重用。函式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 函式read和write
函式read嘗試從fd中讀取nbyte位元組的資料到buf開始的快取裡,讀取成功時返回讀取的位元組數目。函式write把buf處開始的nbyte位元組資料寫入fd引用的檔案裡,寫入成功時返回實際寫入的位元組數目。
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 函式lseek
函式lseek用於重新定位檔案讀寫的偏移位置。引數whence取值為SEEK_SET、SEEK_CUR或SEEK_END,定義在檔案third_party\musl\porting\liteos_m\kernel\include\fcntl.h。
- SEEK_SET
偏移設定在offset位元組處。 - SEEK_CUR
偏移設定在當前位置加上offset位元組處。 - SEEK_END
偏移設定在檔案大小加上offset位元組處。
函式執行成功時,返回值為從檔案開頭的偏移位元組數值。
off_t lseek(int fd, off_t offset, int whence) { return LOS_Lseek(fd, offset, whence); }}
1.6 函式fstat、stat和statfs
函式fstat和stat用於獲取檔案的狀態state,引數引數分別是檔案描述符和檔案路徑。引數中的struct stat結構體定義在檔案third_party\musl\porting\liteos_m\kernel\include\bits\stat.h中。
函式statfs返回檔案系統統計statistics資料,結構體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 函式mkdir、opendir、readir、closedir和rmdrir
函式mkdir用於建立一個目錄,目錄名稱由引數path指定。引數mode指定目錄許可權。建立成功返回0,否則返回-1。
函式opendir用於開啟一個目錄流a directory stream,目錄名稱由引數dirName指定,返回一個執行目錄劉的指標。發生錯誤時,返回NULL,並設定errno。返回值型別DIR是struct __dirstream的別名,定義在檔案中third_party\musl\porting\liteos_m\kernel\include\dirent.h。可以訪問https://linux.die.net/man/3/opendir瞭解更多關於該函式的資訊。
函式readdir用於讀取一個目錄,返回一個struct dirent結構體指標,代表目錄流DIR *dir中的下一個目錄條目directory entry。到達目錄流尾部或錯誤時,返回NULL。結構體定義在檔案third_party\musl\porting\liteos_m\kernel\include\bits\dirent.h中。 可以訪問https://linux.die.net/man/3/readdir瞭解更多關於該函式的資訊。
函式closedir用於關閉一個目錄。函式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 函式fsync
函式mkdir用於同步記憶體中所有已修改的檔案資料到儲存裝置。可以訪問https://linux.die.net/man/3/fsync瞭解更多關於該函式的資訊。
int fsync(int fd) { return LOS_Fsync(fd); }
1.9 函式rename
函式rename用於重新命名一個檔案。可以訪問https://linux.die.net/man/3/rename瞭解更多關於該函式的資訊。
int rename(const char *oldName, const char *newName) { return LOS_Rename(oldName, newName); }
1.10 函式ftruncate
函式ftruncate用於截斷一個檔案到指定的長度。可以訪問https://linux.die.net/man/3/ftruncate瞭解更多關於該函式的資訊。
int ftruncate(int fd, off_t length) { return LOS_Ftruncate(fd, length); }
2、Musl LibC記憶體分配釋放
LiteOS-M核心提供了記憶體分配釋放函式。這些是標準的POSIX介面,如果想了解其用法,可以參考Section 3: library functions。可以在網頁上搜尋,也可以直接把上述網址和函式名稱進行拼接,如對於malloc()函式,可以直接訪問https://linux.die.net/man/3/malloc。opendir等部分函式需要在網頁上檢視。下文快速記錄下各個函式的使用方法。
2.1 函式malloc、free和memalign
函式malloc和free分別呼叫核心記憶體模組的介面來實現記憶體申請和釋放。函式memalign可以以指定的記憶體對齊大小來申請記憶體。
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); }
2.2 函式malloc、free和memalign
函式calloc在記憶體的動態儲存區中分配nitems個長度為size的連續空間,函式返回一個指向分配起始地址的指標;如果分配不成功,返回NULL。
函式zalloc和malloc的區別是,申請成功後,對申請的記憶體區域置0。函式realloc用於重新申請一塊記憶體區域。
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); }
小結
本文學習了LiteOS-M核心Musl LibC的實現,特別是檔案系統和記憶體分配釋放部分。時間倉促和能力關係,如有失誤,歡迎指正。感謝閱讀,如有任何問題、建議,都可以部落格下留言給我,謝謝。
參考資料
- library functions - Linux man pages
- system calls - Linux man pages