posix 接口注解.

    百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码
    国内:https://weharmony.21cloudbox.com
    国外:https://weharmony.github.io
上级 30a3fbf6
......@@ -166,7 +166,13 @@ STATIC INLINE INT32 LOS_AtomicAdd(Atomic *v, INT32 addVal)
: "r"(v), "r"(addVal)
: "cc");
} while (__builtin_expect(status != 0, 0));
/****************************************************
__builtin_expect是结束循环的判断语句,将最有可能执行的分支告诉编译器。
这个指令的写法为:__builtin_expect(EXP, N)。
意思是:EXP==N 的概率很大。
综合理解__builtin_expect(status != 0, 0)
说的是status = 0 的可能性很大,不成功就会重新来一遍,直到strex更新成(status == 0)为止.
****************************************************/
return val;
}
......
......@@ -32,7 +32,7 @@
#include "los_typedef.h"
#include "los_memory.h"
//支持posix方式内存对齐
int posix_memalign(void **memAddr, size_t alignment, size_t size)
{
if ((alignment == 0) || ((alignment & (alignment - 1)) != 0) || ((alignment % sizeof(void *)) != 0)) {
......
......@@ -49,10 +49,10 @@ extern "C" {
* Thread control data structure
* Per-thread information needed by POSIX
*/
typedef struct {
pthread_attr_t attr; /* Current thread attributes */
pthread_t id; /* My thread ID */
LosTaskCB *task; /* pointer to Huawei LiteOS thread object */
typedef struct { //线程控制块
pthread_attr_t attr; /* Current thread attributes *///线程属性
pthread_t id; /* My thread ID *///线程ID
LosTaskCB *task; /* pointer to Huawei LiteOS thread object */// 指向liteos的任务
CHAR name[PTHREAD_DATA_NAME_MAX]; /* name string for debugging */
UINT8 state; /* Thread state */
UINT8 cancelstate; /* Cancel state of thread */
......
......@@ -38,12 +38,13 @@
#include "los_process_pri.h"
#include "los_sched_pri.h"
// 本文件实现 liteos task 适配 pthread
/*
* Array of pthread control structures. A pthread_t object is
* "just" an index into this array.
*/
STATIC _pthread_data g_pthreadData[LOSCFG_BASE_CORE_TSK_LIMIT + 1];
STATIC _pthread_data g_pthreadData[LOSCFG_BASE_CORE_TSK_LIMIT + 1];//
/* Count of number of threads that have exited and not been reaped. */
STATIC INT32 g_pthreadsExited = 0;
......@@ -58,14 +59,14 @@ UINTPTR g_pthreadCanceledDummyVar;
* Private version of pthread_self() that returns a pointer to our internal
* control structure.
*/
_pthread_data *pthread_get_self_data(void)
_pthread_data *pthread_get_self_data(void)//获取当前线程信息
{
UINT32 runningTaskPID = ((LosTaskCB *)(OsCurrTaskGet()))->taskID;
UINT32 runningTaskPID = ((LosTaskCB *)(OsCurrTaskGet()))->taskID;//当前线程
_pthread_data *data = &g_pthreadData[runningTaskPID];
return data;
}
//获取线程控制块
_pthread_data *pthread_get_data(pthread_t id)
{
_pthread_data *data = NULL;
......@@ -136,7 +137,7 @@ STATIC VOID PthreadReap(VOID)
}
}
}
//设置线程的属性
STATIC VOID SetPthreadAttr(const _pthread_data *self, const pthread_attr_t *attr, pthread_attr_t *outAttr)
{
/*
......@@ -184,7 +185,7 @@ STATIC VOID SetPthreadDataAttr(const pthread_attr_t *userAttr, const pthread_t t
created->stackmem = taskCB->topOfStack;
created->thread_data = NULL;
}
//线程控制块初始化
STATIC UINT32 InitPthreadData(pthread_t threadID, pthread_attr_t *userAttr,
const CHAR name[], size_t len)
{
......@@ -198,7 +199,7 @@ STATIC UINT32 InitPthreadData(pthread_t threadID, pthread_attr_t *userAttr,
PRINT_ERR("%s: %d, err: %d\n", __FUNCTION__, __LINE__, err);
return LOS_NOK;
}
userAttr->stacksize = taskCB->stackSize;
userAttr->stacksize = taskCB->stackSize;//内核栈大小
err = OsSetTaskName(taskCB, created->name, FALSE);
if (err != LOS_OK) {
PRINT_ERR("%s: %d, err: %d\n", __FUNCTION__, __LINE__, err);
......@@ -206,7 +207,7 @@ STATIC UINT32 InitPthreadData(pthread_t threadID, pthread_attr_t *userAttr,
}
#if (LOSCFG_KERNEL_SMP == YES)
if (userAttr->cpuset.__bits[0] > 0) {
taskCB->cpuAffiMask = (UINT16)userAttr->cpuset.__bits[0];
taskCB->cpuAffiMask = (UINT16)userAttr->cpuset.__bits[0];//CPU亲和力掩码
}
#endif
......@@ -456,7 +457,7 @@ int pthread_detach(pthread_t thread)
return ret;
}
//设置调度参数
int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param *param)
{
_pthread_data *data = NULL;
......@@ -747,7 +748,7 @@ void pthread_testcancel(void)
}
/* Get current thread id. */
pthread_t pthread_self(void)
pthread_t pthread_self(void)//获取当前线程ID
{
_pthread_data *data = pthread_get_self_data();
......
......@@ -31,23 +31,23 @@
#include "pthread.h"
#include "pprivate.h"
//https://docs.oracle.com/cd/E19253-01/819-7051/6n919hpac/index.html
//线程属性初始化
int pthread_attr_init(pthread_attr_t *attr)
{
if (attr == NULL) {
return EINVAL;
}
attr->detachstate = PTHREAD_CREATE_JOINABLE;
attr->schedpolicy = SCHED_RR;
attr->schedparam.sched_priority = LOSCFG_BASE_CORE_TSK_DEFAULT_PRIO;
attr->inheritsched = PTHREAD_INHERIT_SCHED;
attr->scope = PTHREAD_SCOPE_PROCESS;
attr->stackaddr_set = 0;
attr->stackaddr = NULL;
attr->stacksize_set = 1;
attr->stacksize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
attr->detachstate = PTHREAD_CREATE_JOINABLE;//
attr->schedpolicy = SCHED_RR;//抢占式调度
attr->schedparam.sched_priority = LOSCFG_BASE_CORE_TSK_DEFAULT_PRIO;//调度优先级
attr->inheritsched = PTHREAD_INHERIT_SCHED;//继承调度
attr->scope = PTHREAD_SCOPE_PROCESS;//进程范围
attr->stackaddr_set = 0; //暂未内核栈开始地址
attr->stackaddr = NULL;//内核栈地址
attr->stacksize_set = 1;//已设置内核栈大小
attr->stacksize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;//默认16K
#if (LOSCFG_KERNEL_SMP == YES)
attr->cpuset.__bits[0] = 0;
......@@ -65,7 +65,7 @@ int pthread_attr_destroy(pthread_attr_t *attr)
/* Nothing to do here... */
return ENOERR;
}
//设置分离状态(分离和联合) 如果创建分离线程 (PTHREAD_CREATE_DETACHED),则该线程一退出,便可重用其线程 ID 和其他资源。
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachState)
{
if ((attr != NULL) && ((detachState == PTHREAD_CREATE_JOINABLE) || (detachState == PTHREAD_CREATE_DETACHED))) {
......@@ -75,7 +75,7 @@ int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachState)
return EINVAL;
}
//获取分离状态
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachState)
{
if ((attr == NULL) || (detachState == NULL)) {
......@@ -86,7 +86,9 @@ int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachState)
return ENOERR;
}
//设置线程的竞争范围(PTHREAD_SCOPE_SYSTEM 或 PTHREAD_SCOPE_PROCESS)。
//使用 PTHREAD_SCOPE_SYSTEM 时,此线程将与系统中的所有线程进行竞争。
//使用 PTHREAD_SCOPE_PROCESS 时,此线程将与进程中的其他线程进行竞争。
int pthread_attr_setscope(pthread_attr_t *attr, int scope)
{
if (attr == NULL) {
......@@ -104,7 +106,7 @@ int pthread_attr_setscope(pthread_attr_t *attr, int scope)
return EINVAL;
}
//获取线程的竞争范围
int pthread_attr_getscope(const pthread_attr_t *attr, int *scope)
{
if ((attr == NULL) || (scope == NULL)) {
......@@ -115,7 +117,8 @@ int pthread_attr_getscope(const pthread_attr_t *attr, int *scope)
return ENOERR;
}
//设置继承的调度策略, PTHREAD_INHERIT_SCHED 表示新建的线程将继承创建者线程中定义的调度策略。
//将忽略在 pthread_create() 调用中定义的所有调度属性。如果使用缺省值 PTHREAD_EXPLICIT_SCHED,则将使用 pthread_create() 调用中的属性
int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
{
if ((attr != NULL) && ((inherit == PTHREAD_INHERIT_SCHED) || (inherit == PTHREAD_EXPLICIT_SCHED))) {
......@@ -125,7 +128,7 @@ int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
return EINVAL;
}
//获取继承的调度策略
int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit)
{
if ((attr == NULL) || (inherit == NULL)) {
......@@ -136,7 +139,7 @@ int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit)
return ENOERR;
}
//设置调度策略,POSIX 标准指定 SCHED_FIFO(先入先出)、SCHED_RR(抢占)或 SCHED_OTHER(实现定义的方法)的调度策略属性。
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
{
if ((attr != NULL) && (policy == SCHED_RR)) {
......@@ -146,7 +149,7 @@ int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
return EINVAL;
}
//获取调度策略
int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
{
if ((attr == NULL) || (policy == NULL)) {
......@@ -157,7 +160,7 @@ int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
return ENOERR;
}
//设置调度参数,调度参数是在 param 结构中定义的。仅支持优先级参数。新创建的线程使用此优先级运行。
int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param)
{
if ((attr == NULL) || (param == NULL)) {
......@@ -170,7 +173,7 @@ int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *p
return ENOERR;
}
//获取调度参数
int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param)
{
if ((attr == NULL) || (param == NULL)) {
......@@ -187,6 +190,7 @@ int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *p
* the memory block allocated for the stack depends on whether the stack
* grows up or down.
*/
//设置栈起始地址,在开始还是结束为堆栈分配的内存块取决于堆栈是向上增长还是向下增长。
int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackAddr)
{
if (attr == NULL) {
......@@ -198,7 +202,7 @@ int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackAddr)
return ENOERR;
}
//获取栈起始地址
int pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackAddr)
{
if (((attr != NULL) && (stackAddr != NULL)) && attr->stackaddr_set) {
......@@ -208,11 +212,11 @@ int pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackAddr)
return EINVAL; /* Stack address not set, return EINVAL. */
}
//设置栈大小
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stackSize)
{
/* Reject inadequate stack sizes */
if ((attr == NULL) || (stackSize < PTHREAD_STACK_MIN)) {
/* Reject inadequate stack sizes *///拒绝不合适的堆栈尺寸
if ((attr == NULL) || (stackSize < PTHREAD_STACK_MIN)) {//size 不应小于系统定义的最小栈大小
return EINVAL;
}
......@@ -221,7 +225,7 @@ int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stackSize)
return ENOERR;
}
//获取栈大小
int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stackSize)
{
/* Reject attempts to get a stack size when one has not been set. */
......@@ -236,7 +240,7 @@ int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stackSize)
/*
* Set the cpu affinity mask
*/
*///cpu集可以认为是一个掩码,每个设置的位都对应一个可以合法调度的 cpu,而未设置的位则对应一个不可调度的 CPU。
int pthread_attr_setaffinity_np(pthread_attr_t* attr, size_t cpusetsize, const cpu_set_t* cpuset)
{
#if (LOSCFG_KERNEL_SMP == YES)
......@@ -248,7 +252,7 @@ int pthread_attr_setaffinity_np(pthread_attr_t* attr, size_t cpusetsize, const c
attr->cpuset.__bits[0] = 0;
return ENOERR;
}
//cpu_set_t这个结构体的理解类似于select中的fd_set,可以理解为cpu集,也是通过约定好的宏来进行清除、设置以及判断
if ((cpusetsize != sizeof(cpu_set_t)) || (cpuset->__bits[0] > LOSCFG_KERNEL_CPU_MASK)) {
return EINVAL;
}
......
......@@ -35,7 +35,24 @@
#include "time_posix.h"
#include "los_atomic.h"
#include "los_event_pri.h"
/************************************************************
条件变量属性
使用条件变量可以以原子方式阻塞线程,直到某个特定条件为真为止。条件变量始终与互斥锁一起使用。
使用条件变量,线程可以以原子方式阻塞,直到满足某个条件为止。对条件的测试是在互斥锁(互斥)的保护下进行的。
如果条件为假,线程通常会基于条件变量阻塞,并以原子方式释放等待条件变化的互斥锁。如果另一个线程更改了条件,
该线程可能会向相关的条件变量发出信号,从而使一个或多个等待的线程执行以下操作:
唤醒
再次获取互斥锁
重新评估条件
在以下情况下,条件变量可用于在进程之间同步线程:
线程是在可以写入的内存中分配的
内存由协作进程共享
调度策略可确定唤醒阻塞线程的方式。对于缺省值 SCHED_OTHER,将按优先级顺序唤醒线程。
https://docs.oracle.com/cd/E19253-01/819-7051/sync-13528/index.html
https://docs.oracle.com/cd/E19253-01/819-7051/6n919hpai/index.html#sync-59145
************************************************************/
#define BROADCAST_EVENT 1
#define COND_COUNTER_STEP 0x0004U
......@@ -50,25 +67,25 @@ STATIC INLINE INT32 CondInitCheck(const pthread_cond_t *cond)
}
return 0;
}
//获取条件变量的范围
int pthread_condattr_getpshared(const pthread_condattr_t *attr, int *shared)
{
if ((attr == NULL) || (shared == NULL)) {
return EINVAL;
}
*shared = PTHREAD_PROCESS_PRIVATE;
*shared = PTHREAD_PROCESS_PRIVATE;// PTHREAD_PROCESS_PRIVATE,则仅有那些由同一个进程创建的线程才能够处理该互斥锁。
return 0;
}
//设置条件变量的范围
int pthread_condattr_setpshared(pthread_condattr_t *attr, int shared)
{
(VOID)attr;
if ((shared != PTHREAD_PROCESS_PRIVATE) && (shared != PTHREAD_PROCESS_SHARED)) {
return EINVAL;
}
//如果 pshared 属性在共享内存中设置为 PTHREAD_PROCESS_SHARED,则其所创建的条件变量可以在多个进程中的线程之间共享。
if (shared != PTHREAD_PROCESS_PRIVATE) {
return ENOSYS;
}
......@@ -115,7 +132,7 @@ int pthread_cond_destroy(pthread_cond_t *cond)
cond->mutex = NULL;
return ENOERR;
}
//条件变量初始化
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
{
int ret = ENOERR;
......@@ -154,7 +171,7 @@ STATIC VOID PthreadCondValueModify(pthread_cond_t *cond)
}
}
}
//解除阻塞所有线程
int pthread_cond_broadcast(pthread_cond_t *cond)
{
int ret = ENOERR;
......@@ -170,14 +187,14 @@ int pthread_cond_broadcast(pthread_cond_t *cond)
PthreadCondValueModify(cond);
(VOID)LOS_EventWrite(&(cond->event), BROADCAST_EVENT);
(VOID)LOS_EventWrite(&(cond->event), BROADCAST_EVENT);//写事件
return ret;
}
(VOID)pthread_mutex_unlock(cond->mutex);
return ret;
}
//解除阻塞一个线程
int pthread_cond_signal(pthread_cond_t *cond)
{
int ret = ENOERR;
......@@ -191,7 +208,7 @@ int pthread_cond_signal(pthread_cond_t *cond)
cond->count--;
(VOID)pthread_mutex_unlock(cond->mutex);
PthreadCondValueModify(cond);
(VOID)OsEventWriteOnce(&(cond->event), 0x01);
(VOID)OsEventWriteOnce(&(cond->event), 0x01);//只写一次,也就是解除一个线程的阻塞
return ret;
}
......@@ -245,7 +262,7 @@ STATIC INT32 ProcessReturnVal(pthread_cond_t *cond, INT32 val)
}
return ret;
}
//在指定的时间之前阻塞,函数会一直阻塞,直到该条件获得信号,或者最后一个参数所指定的时间已过为止。
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
const struct timespec *absTime)
{
......@@ -296,7 +313,7 @@ int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
pthread_testcancel();
return ret;
}
//基于条件变量阻塞,阻塞的线程可以通过 pthread_cond_signal() 或 pthread_cond_broadcast() 唤醒
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
{
int ret;
......
......@@ -30,15 +30,33 @@
*/
#include "pthread.h"
/****************************************************************************
当 pthread_mutex_lock() 返回时,该互斥锁已被锁定。调用线程是该互斥锁的属主。
如果该互斥锁已被另一个线程锁定和拥有,则调用线程将阻塞,直到该互斥锁变为可用为止。
如果互斥锁类型为 PTHREAD_MUTEX_NORMAL,则不提供死锁检测。尝试重新锁定互斥锁会导致死锁。
如果某个线程尝试解除锁定的互斥锁不是由该线程锁定或未锁定,则将产生不确定的行为。
int pthread_mutexattr_init(pthread_mutexattr_t *attr)
{
如果互斥锁类型为 PTHREAD_MUTEX_ERRORCHECK,则会提供错误检查。如果某个线程尝试重新锁定的互斥锁已经由该线程锁定,
则将返回错误。如果某个线程尝试解除锁定的互斥锁不是由该线程锁定或者未锁定,则将返回错误。
如果互斥锁类型为 PTHREAD_MUTEX_RECURSIVE,则该互斥锁会保留锁定计数这一概念。线程首次成功获取互斥锁时,
锁定计数会设置为 1。线程每重新锁定该互斥锁一次,锁定计数就增加 1。线程每解除锁定该互斥锁一次,锁定计数就减小 1。 锁定计数达到 0 时,该互斥锁即可供其他线程获取。如果某个线程尝试解除锁定的互斥锁不是由该线程锁定或者未锁定,则将返回错误。
如果互斥锁类型是 PTHREAD_MUTEX_DEFAULT,则尝试以递归方式锁定该互斥锁将产生不确定的行为。
对于不是由调用线程锁定的互斥锁,如果尝试解除对它的锁定,则会产生不确定的行为。如果尝试解除锁定尚未锁定的互斥锁,
则会产生不确定的行为。
参考链接: https://docs.oracle.com/cd/E19253-01/819-7051/sync-12/index.html
本文件是对鸿蒙轻内核互斥锁的封装
****************************************************************************/
int pthread_mutexattr_init(pthread_mutexattr_t *attr)//初始化互斥锁
{//如果互斥锁已初始化,则它会处于未锁定状态。互斥锁可以位于进程之间共享的内存中或者某个进程的专用内存中。
unsigned int ret = LOS_MuxAttrInit(attr);
if (ret != LOS_OK) {
return (int)ret;
}
//当其他线程正在使用某个互斥锁时,请勿重新初始化或销毁该互斥锁。如果任一操作没有正确完成,将会导致程序失败。如果要重新初始化或销毁某个互斥锁,则应用程序必须确保当前未使用该互斥锁。
#if defined POSIX_MUTEX_DEFAULT_INHERIT
attr->protocol = PTHREAD_PRIO_INHERIT;
#elif defined POSIX_MUTEX_DEFAULT_PROTECT
......@@ -97,7 +115,7 @@ int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
/* Initialize mutex. If mutexAttr is NULL, use default attributes. */
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexAttr)
{
{//初始化互斥锁。 如果 mutexAttr 为 NULL,则使用默认属性。
unsigned int ret = LOS_MuxInit(mutex, mutexAttr);
if ((ret == LOS_OK) && (mutexAttr == NULL)) {
#if defined POSIX_MUTEX_DEFAULT_INHERIT
......
......@@ -59,6 +59,7 @@ int sched_get_priority_max(int policy)
/*
* This API is Linux-specific, not conforming to POSIX.
*/
//此 API 是 Linux 特定的,不符合 POSIX
int sched_setaffinity(pid_t pid, size_t set_size, const cpu_set_t* set)
{
#if (LOSCFG_KERNEL_SMP == YES)
......
......@@ -2064,7 +2064,7 @@ ERROR_WITH_DIR:
fatfs_closedir(vp, dir);
return -fatfs_2_vfs(result);
}
//fatfs 实现 vfs 接口层
//fatfs 实现vnode接口
struct VnodeOps fatfs_vops = {
/* file ops */
.Getattr = fatfs_stat,
......@@ -2105,6 +2105,6 @@ struct file_operations_vfs fatfs_fops = {
.ioctl = fatfs_ioctl,
};
FSMAP_ENTRY(fat_fsmap, "vfat", fatfs_mops, FALSE, TRUE);
FSMAP_ENTRY(fat_fsmap, "vfat", fatfs_mops, FALSE, TRUE);//注册文件映射
#endif /* LOSCFG_FS_FAT */
......@@ -41,6 +41,8 @@
#define VNODE_FLAG_MOUNT_ORIGIN 2 //原装载点
#define DEV_PATH_LEN 5
/******************************************************************
Linux系统使用struct inode作为数据结构名称。BSD派生的系统,使用vnode名称,其中v表示“virtual file system”
Linux 链接分两种,一种被称为硬链接(Hard Link),另一种被称为符号链接(Symbolic Link)。默认情况下,ln 命令产生硬链接。
硬连接
......@@ -79,8 +81,8 @@ enum VnodeType {//节点类型
VNODE_TYPE_UNKNOWN, /* unknown type */ //未知类型
VNODE_TYPE_REG, /* regular file */ //正则文件(普通文件)
VNODE_TYPE_DIR, /* directory */ //目录
VNODE_TYPE_BLK, /* block device */ //块设备驱动
VNODE_TYPE_CHR, /* char device */ //字符设备驱动
VNODE_TYPE_BLK, /* block device */ //块设备
VNODE_TYPE_CHR, /* char device */ //字符设备
VNODE_TYPE_BCHR, /* block char mix device *///块和字符设备混合
VNODE_TYPE_FIFO, /* pipe */ //管道文件
VNODE_TYPE_LNK, /* link */ //链接,这里的链接指的是上层硬链接概念
......@@ -100,7 +102,7 @@ struct IATTR;
因此 vop ,fop 都是接口, data 因设备不同而不同.
*/
struct Vnode {
enum VnodeType type; /* vnode type */ //节点类型
enum VnodeType type; /* vnode type */ //节点类型 (文件|目录|链接...)
int useCount; /* ref count of users *///节点引用(链接)数,即有多少文件名指向这个vnode,即上层理解的硬链接数
uint32_t hash; /* vnode hash */ //节点哈希值
uint uid; /* uid for dac */ //DAC用户ID
......@@ -119,22 +121,29 @@ struct Vnode {
struct Mount *newMount; /* fs info about who mount on this vnode */ //挂载在这个节点上的文件系统
};
/*
虚拟文件系统接口,具体的文件系统只需实现这些接口函数就完成了鸿蒙系统的接入.
VnodeOps 系列函数是基于索引节点的操作.
虚拟节点操作接口,具体的文件系统只需实现这些接口函数来操作vnode.
VnodeOps 系列函数是对节点本身的操作.
*/
struct VnodeOps {
int (*Create)(struct Vnode *parent, const char *name, int mode, struct Vnode **vnode);//创建
int (*Lookup)(struct Vnode *parent, const char *name, int len, struct Vnode **vnode);//查询
int (*Open)(struct Vnode *vnode, int fd, int mode, int flags);//打开
int (*Close)(struct Vnode *vnode);//关闭
int (*Reclaim)(struct Vnode *vnode);//回收
int (*Unlink)(struct Vnode *parent, struct Vnode *vnode, char *fileName);//取消链接
int (*Rmdir)(struct Vnode *parent, struct Vnode *vnode, char *dirName);//删除目录
int (*Mkdir)(struct Vnode *parent, const char *dirName, mode_t mode, struct Vnode **vnode);//创建目录
int (*Readdir)(struct Vnode *vnode, struct fs_dirent_s *dir);//读目录
int (*Opendir)(struct Vnode *vnode, struct fs_dirent_s *dir);//打开目录
int (*Rewinddir)(struct Vnode *vnode, struct fs_dirent_s *dir);//定位目录函数
int (*Closedir)(struct Vnode *vnode, struct fs_dirent_s *dir);//关闭目录
int (*Create)(struct Vnode *parent, const char *name, int mode, struct Vnode **vnode);//创建节点
int (*Lookup)(struct Vnode *parent, const char *name, int len, struct Vnode **vnode);//查询节点
int (*Open)(struct Vnode *vnode, int fd, int mode, int flags);//打开节点
int (*Close)(struct Vnode *vnode);//关闭节点
int (*Reclaim)(struct Vnode *vnode);//回收节点
int (*Unlink)(struct Vnode *parent, struct Vnode *vnode, char *fileName);//取消硬链接
int (*Rmdir)(struct Vnode *parent, struct Vnode *vnode, char *dirName);//删除目录节点
int (*Mkdir)(struct Vnode *parent, const char *dirName, mode_t mode, struct Vnode **vnode);//创建目录节点
/*
创建一个目录时,实际做了3件事:在其“父目录文件”中增加一个条目;分配一个inode;再分配一个存储块,
用来保存当前被创建目录包含的文件与子目录。被创建的“目录文件”中自动生成两个子目录的条目,名称分别是:“.”和“..”。
前者与该目录具有相同的inode号码,因此是该目录的一个“硬链接”。后者的inode号码就是该目录的父目录的inode号码。
所以,任何一个目录的"硬链接"总数,总是等于它的子目录总数(含隐藏目录)加2。即每个“子目录文件”中的“..”条目,
加上它自身的“目录文件”中的“.”条目,再加上“父目录文件”中的对应该目录的条目。
*/
int (*Readdir)(struct Vnode *vnode, struct fs_dirent_s *dir);//读目录节点
int (*Opendir)(struct Vnode *vnode, struct fs_dirent_s *dir);//打开目录节点
int (*Rewinddir)(struct Vnode *vnode, struct fs_dirent_s *dir);//定位目录节点
int (*Closedir)(struct Vnode *vnode, struct fs_dirent_s *dir);//关闭目录节点
int (*Getattr)(struct Vnode *vnode, struct stat *st);//获取节点属性
int (*Setattr)(struct Vnode *vnode, struct stat *st);//设置节点属性
int (*Chattr)(struct Vnode *vnode, struct IATTR *attr);//改变节点属性(change attr)
......
......@@ -263,7 +263,7 @@ int VfsJffs2Lookup(struct Vnode *parentVnode, const char *path, int len, struct
LOS_MuxUnlock(&g_jffs2FsLock);
return 0;
}
//创建一个jffs2 索引节点
int VfsJffs2Create(struct Vnode *parentVnode, const char *path, int mode, struct Vnode **ppVnode)
{
int ret;
......@@ -804,7 +804,7 @@ const struct MountOps jffs_operations = {//jffs对mount接口实现
.Unmount = VfsJffs2Unbind,
.Statfs = VfsJffs2Statfs,
};
//jffs2 节点视角的操作实现
struct VnodeOps g_jffs2Vops = {
.Lookup = VfsJffs2Lookup,
.Create = VfsJffs2Create,
......@@ -822,7 +822,7 @@ struct VnodeOps g_jffs2Vops = {
.Truncate = VfsJffs2Truncate,
.Truncate64 = VfsJffs2Truncate64,
};
//jffs2 文件视角的操作实现
struct file_operations_vfs g_jffs2Fops = {
.read = VfsJffs2Read,
.write = VfsJffs2Write,
......
......@@ -78,7 +78,7 @@ typedef unsigned short fmode_t;
#define FMODE_READ ((fmode_t)0x1)
struct ProcFile;
//操作pro file的抽象接口,proc本质是个内存文件系统,
//真正最后能操作pro file的接口,proc本质是个内存文件系统, vfs - > ProcFileOperations
struct ProcFileOperations {
char *name;
ssize_t (*write)(struct ProcFile *pf, const char *buf, size_t count, loff_t *ppos);
......@@ -87,10 +87,10 @@ struct ProcFileOperations {
int (*read)(struct SeqBuf *m, void *v);
};
//proc 目录/文件项, @notethinking 直接叫 ProcEntry不香吗 ?
struct ProcDirEntry {
struct ProcDirEntry {//这才是能操作 /proc的 真正结构体
mode_t mode; //模式(读|写...)
int flags; //标签
const struct ProcFileOperations *procFileOps;//驱动程序
const struct ProcFileOperations *procFileOps;//驱动程序,每个 /proc 下目录的驱动程序都不一样
struct ProcFile *pf;//文件指针
struct ProcDirEntry *next, *parent, *subdir;//当前目录项的关系项
void *data;
......
......@@ -37,7 +37,7 @@
#include "fs/file.h"
#include "internal.h"
//显示文件系统类型,将被作为回调函数回调
//显示文件系统类型,将被作为回调函数回调 cat /proc/mounts 显示的每项内容
static int ShowType(const char *mountPoint, struct statfs *statBuf, void *arg)
{
struct SeqBuf *seqBuf = (struct SeqBuf *)arg;
......@@ -45,20 +45,20 @@ static int ShowType(const char *mountPoint, struct statfs *statBuf, void *arg)
char *name = NULL;
switch (statBuf->f_type) {//目前鸿蒙支持的文件系统
case PROCFS_MAGIC:
case PROCFS_MAGIC: //虚拟文件系统,通过它可以使鸿蒙在内核空间和用户空间之间进行通信
type = "proc";
name = "proc";
break;
case JFFS2_SUPER_MAGIC:
type = "jffs2";
type = "jffs2"; //基于 nor flash的文件系统
name = "jffs2";
break;
case NFS_SUPER_MAGIC:
case NFS_SUPER_MAGIC://网络文件系统
type = "nfs";
name = "nfs";
break;
case TMPFS_MAGIC:
type = "tmpfs";
case TMPFS_MAGIC://tmpfs /mnt/wsl windows10的 wsl 实现是 tmpfs方式
type = "tmpfs"; //内存文件系统
name = "tmpfs";
break;
case MSDOS_SUPER_MAGIC:
......@@ -87,7 +87,7 @@ static int MountsProcFill(struct SeqBuf *m, void *v)
}
//实现 操作proc file 接口,也可理解为驱动程序不同
static const struct ProcFileOperations MOUNTS_PROC_FOPS = {
.read = MountsProcFill,
.read = MountsProcFill,// /proc/mounts 只能被读取
};
void ProcMountsInit(void)
......@@ -98,6 +98,6 @@ void ProcMountsInit(void)
return;
}
pde->procFileOps = &MOUNTS_PROC_FOPS;
pde->procFileOps = &MOUNTS_PROC_FOPS;//操作 /proc/mounts 的具体实现
}
......@@ -48,19 +48,19 @@ void ProcFsInit(void)
return;
}
//装载文件系统
ret = mount(NULL, PROCFS_MOUNT_POINT, "procfs", 0, NULL);
ret = mount(NULL, PROCFS_MOUNT_POINT, "procfs", 0, NULL);//将null 挂到 /proc 上
if (ret) {
PRINT_ERR("mount procfs err %d\n", ret);
return;
}
ProcMountsInit();//初始化 /pro/mounts
ProcMountsInit();//初始化 /proc/mounts
#if defined(LOSCFG_SHELL_CMD_DEBUG) && defined(LOSCFG_KERNEL_VM)
ProcVmmInit();//初始化 /pro/vmm
ProcVmmInit();//初始化 /proc/vmm
#endif
ProcProcessInit();//初始化 /pro/process
ProcUptimeInit();//初始化 /pro/uptime
ProcKernelTraceInit();//初始化 /pro/ktrace
ProcProcessInit();//初始化 /proc/process
ProcUptimeInit();//初始化 /proc/uptime
ProcKernelTraceInit();//初始化 /proc/ktrace
}
LOS_MODULE_INIT(ProcFsInit, LOS_INIT_LEVEL_KMOD_EXTENDED);
......
......@@ -40,28 +40,42 @@
#include "internal.h"
#define PROCFS_DEFAULT_MODE 0555
/******************************************************************
鸿蒙的/proc目录是一种文件系统,即proc文件系统。与其它常见的文件系统不同的是,/proc是一种伪文件系统(也即虚拟文件系统),
存储的是当前内核运行状态的一系列特殊文件,用户可以通过这些文件查看有关系统硬件及当前正在运行进程的信息,
甚至可以通过更改其中某些文件来改变内核的运行状态。
基于/proc文件系统如上所述的特殊性,其内的文件也常被称作虚拟文件,并具有一些独特的特点。
例如,其中有些文件虽然使用查看命令查看时会返回大量信息,但文件本身的大小却会显示为0字节。
此外,这些特殊文件中大多数文件的时间及日期属性通常为当前系统时间和日期,这跟它们随时会被刷新(存储于RAM中)有关。
为了查看及使用上的方便,这些文件通常会按照相关性进行分类存储于不同的目录甚至子目录中,
如/proc/mounts 目录中存储的就是当前系统上所有装载点的相关信息,
大多数虚拟文件可以使用文件查看命令如cat、more或者less进行查看,有些文件信息表述的内容可以一目了然,
*******************************************************************/
#ifdef LOSCFG_FS_PROC //使能 /proc 功能
static struct VnodeOps g_procfsVops; // proc 文件系统
static struct file_operations_vfs g_procfsFops;
//通过节点获取私有内存对象,注意要充分理解 node->data 的作用,那是个可以通天的神奇变量.
static struct ProcDirEntry *VnodeToEntry(struct Vnode *node)
{
return (struct ProcDirEntry *)(node->data);
}
//创建节点,绑定实体对象
static struct Vnode *EntryToVnode(struct ProcDirEntry *entry)
{
struct Vnode *node = NULL;
(void)VnodeAlloc(&g_procfsVops, &node);
node->fop = &g_procfsFops;
node->data = entry;
node->type = entry->type;
if (node->type == VNODE_TYPE_DIR) {
node->mode = S_IFDIR | PROCFS_DEFAULT_MODE;
(void)VnodeAlloc(&g_procfsVops, &node);//申请一个 vnode节点,并设置操作节点的实现函数
node->fop = &g_procfsFops;//设置文件操作系列函数
node->data = entry;//绑定实体
node->type = entry->type;//实体类型 (文件|目录)
if (node->type == VNODE_TYPE_DIR) {//文件类型
node->mode = S_IFDIR | PROCFS_DEFAULT_MODE;//给节点增加目录标签
} else {
node->mode = S_IFREG | PROCFS_DEFAULT_MODE;
node->mode = S_IFREG | PROCFS_DEFAULT_MODE;//给节点增加文件标签
}
return node;
}
......@@ -78,7 +92,7 @@ int VfsProcfsTruncate(struct Vnode *pVnode, off_t len)
{
return 0;
}
//创建vnode节点,并绑定私有内容项
int VfsProcfsCreate(struct Vnode* parent, const char *name, int mode, struct Vnode **vnode)
{
int ret;
......@@ -177,16 +191,16 @@ int VfsProcfsLookup(struct Vnode *parent, const char *name, int len, struct Vnod
(*vpp)->parent = parent;
return LOS_OK;
}
//装载实现,将mount挂到vnode节点上
//装载实现,找个vnode节点挂上去
int VfsProcfsMount(struct Mount *mnt, struct Vnode *device, const void *data)
{
struct Vnode *vp = NULL;
int ret;
spin_lock_init(&procfsLock);
procfsInit = true;
procfsInit = true; //已初始化 /proc 模块
ret = VnodeAlloc(&g_procfsVops, &vp);
ret = VnodeAlloc(&g_procfsVops, &vp);//分配一个节点
if (ret != 0) {
return -ENOMEM;
}
......@@ -198,10 +212,10 @@ int VfsProcfsMount(struct Mount *mnt, struct Vnode *device, const void *data)
mnt->data = NULL;
mnt->vnodeCovered = vp;
vp->type = root->type;
if (vp->type == VNODE_TYPE_DIR) {
vp->mode = S_IFDIR | PROCFS_DEFAULT_MODE;
if (vp->type == VNODE_TYPE_DIR) {//目录节点
vp->mode = S_IFDIR | PROCFS_DEFAULT_MODE;//贴上目录标签
} else {
vp->mode = S_IFREG | PROCFS_DEFAULT_MODE;
vp->mode = S_IFREG | PROCFS_DEFAULT_MODE;//贴上文件标签
}
return LOS_OK;
......@@ -290,8 +304,8 @@ int VfsProcfsOpen(struct file *filep)
if (filep == NULL) {
return -EINVAL;
}
struct Vnode *node = filep->f_vnode;
struct ProcDirEntry *pde = VnodeToEntry(node);
struct Vnode *node = filep->f_vnode;//找到vnode节点
struct ProcDirEntry *pde = VnodeToEntry(node);//拿到私有数据(内存对象)
if (ProcOpen(pde->pf) != OK) {
return -ENOMEM;
}
......
......@@ -47,7 +47,7 @@ static const struct ProcFileOperations PROCESS_PROC_FOPS = {
//创建进程相关信息 /proc/process
void ProcProcessInit(void)
{
struct ProcDirEntry *pde = CreateProcEntry("process", 0, NULL);
struct ProcDirEntry *pde = CreateProcEntry("process", 0, NULL);//创建 /proc/process
if (pde == NULL) {
PRINT_ERR("create /proc/process error!\n");
return;
......
......@@ -372,7 +372,7 @@ struct ProcDirEntry *CreateProcEntry(const char *name, mode_t mode, struct ProcD
}
return pde;
}
//释放proc
static void FreeProcEntry(struct ProcDirEntry *entry)
{
if (entry == NULL) {
......@@ -384,7 +384,7 @@ static void FreeProcEntry(struct ProcDirEntry *entry)
}
free(entry);
}
//释放
void ProcFreeEntry(struct ProcDirEntry *pn)
{
if (atomic_dec_and_test(&pn->count))
......
......@@ -79,5 +79,5 @@ LIST_HEAD* GetMountList()
}
LOS_ListInit(g_mountList);//初始化全局链表
}
return g_mountList;
return g_mountList;//所有文件系统的挂载信息
}
......@@ -42,7 +42,25 @@ static int g_totalVnodeSize = 0; /* total vnode size */ //总节点数量
static LosMux g_vnodeMux; //操作链表互斥量
static struct Vnode *g_rootVnode = NULL;//根节点
static struct VnodeOps g_devfsOps;//虚拟设备节点操作
static struct VnodeOps g_devfsOps;//设备文件系统节点操作
/*********************************************************
linux下有专门的文件系统(devfs | sysfs)用来对设备进行管理,鸿蒙目前只支持 devfs方式
devfs和sysfs都是和proc一样,是一个虚拟的文件系统,提供了一种类似于文件的方法来管理位于/dev目录下的所有设备,
/dev目录下的每一个文件都对应的是一个设备,至于当前该设备存在与否不重要,先把坑位占了.
devfs:设备文件系统
提供类似于文件的方法来管理位于/dev目录下的设备
1.根目录/dev
设备文件创建
创建根文件系统时创建基本的,比如console,tty*等等
设备驱动加载时创建相应的设备文件
2.特殊设备文件
/dev/console
/dev/null /dev/zero :黑洞文件
3.缺点
不确定的设备映射,有时一个设备映射的设备文件可能不同,假如挂载的u盘可能对应sda也可能对应sdb
没有足够的主/辅设备号,当设备过多的时候,显然会成为一个问题
**********************************************************/
#define ENTRY_TO_VNODE(ptr) LOS_DL_LIST_ENTRY(ptr, struct Vnode, actFreeEntry) //通过局部(actFreeEntry)找到整体(Vnode)
#define VNODE_LRU_COUNT 10 //最多回收数量
......@@ -75,7 +93,7 @@ int VnodesInit(void)
}
LOS_ListInit(&g_vnodeFreeList); //初始化空闲的节点链表
LOS_ListInit(&g_vnodeVirtualList); //初始化虚拟设备节点链表
LOS_ListInit(&g_vnodeVirtualList); //初始化虚拟节点链表
LOS_ListInit(&g_vnodeCurrList); //初始化当前(已在使用)的节点链表
retval = VnodeAlloc(NULL, &g_rootVnode);//分配根节点
if (retval != LOS_OK) {
......@@ -139,7 +157,7 @@ struct Vnode *VnodeReclaimLru(void)
}
return item;
}
//申请分配一个 vnode 节点
//申请分配一个 vnode 节点,vop为操作节点的驱动程序
int VnodeAlloc(struct VnodeOps *vop, struct Vnode **newVnode)
{
struct Vnode* vnode = NULL;
......
......@@ -48,7 +48,7 @@ VOID *OsVmBootMemAlloc(size_t len)
{
UINTPTR ptr;
if (g_kHeapInited) {//@note_why 在什么时候会变成true,没找到代码
if (g_kHeapInited) {
VM_ERR("kernel heap has been initialized, do not to use boot memory allocation!");
return NULL;
}
......@@ -78,7 +78,7 @@ UINT32 OsSysMemInit(VOID)
g_kHeapInited = TRUE;
OsInitMappingStartUp();// 映射初始化
#else
g_kHeapInited = TRUE;
g_kHeapInited = TRUE;//堆区完成初始化
#endif
return LOS_OK;
}
......
......@@ -887,7 +887,7 @@ STATIC VOID OsShmCmdUsage(VOID)
"\t-r [shmid], Recycle the specified shared memory about shmid\n"
"\t-h | --help, print shm command usage\n");
}
//共享内存
UINT32 OsShellCmdShm(INT32 argc, const CHAR *argv[])
{
INT32 shmid;
......
......@@ -320,7 +320,7 @@ extern UINT32 __heap_end; // 堆区结束地址
* Starting address of the system memory
*/
#ifndef OS_SYS_MEM_ADDR
#define OS_SYS_MEM_ADDR (&m_aucSysMem1[0])//系统动态内存起始地址
#define OS_SYS_MEM_ADDR (&m_aucSysMem1[0])//系统内存起始地址
#endif
/**
......
......@@ -49,7 +49,7 @@ enum {
LOS_MUX_PRIO_NONE = 0, //线程的优先级和调度不会受到互斥锁影响,先来后到,普通排队.
LOS_MUX_PRIO_INHERIT = 1, //当高优先级的等待低优先级的线程释放锁时,低优先级的线程以高优先级线程的优先级运行。
//当线程解锁互斥量时,线程的优先级自动被将到它原来的优先级
LOS_MUX_PRIO_PROTECT = 2 //详见:OsMuxPendOp中的注解,详细说明了LOS_MUX_PRIO_PROTECT的含义
LOS_MUX_PRIO_PROTECT = 2 //详见: OsMuxPendOp 中的注解,详细说明了LOS_MUX_PRIO_PROTECT的含义
};
enum {
......
git add -A
git commit -m '因同步官方代码,导致调度过程部分需重新加注.调度部分目前代码结构很清晰,将调度和进程,任务彻底剥离开.
git commit -m 'posix 接口注解.
百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码
国内:https://weharmony.21cloudbox.com
国外:https://weharmony.github.io
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册