提交 f90f08b9 编写于 作者: 鸿蒙内核源码分析's avatar 鸿蒙内核源码分析

注解LiteIPC(轻量级进程间通信)模块

    百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码
    鸿蒙研究站 | http://weharmonyos.com (国内)
              | https://weharmony.github.io (国外)
    oschina | https://my.oschina.net/weharmony
    博客园 | https://www.cnblogs.com/weharmony/
    知乎 | https://www.zhihu.com/people/weharmonyos
    csdn | https://blog.csdn.net/kuangyufei
    51cto | https://harmonyos.51cto.com/column/34
    掘金 | https://juejin.cn/user/756888642000808
    公众号 | 鸿蒙研究站 (weharmonyos)
上级 2292c0fc
......@@ -47,20 +47,20 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
/*!
* @brief 内存屏障(英语:Memory barrier),也称内存栅栏,内存栅障,屏障指令等,是一类同步屏障指令,
/*!
* @brief 内存屏障(英语:Memory barrier),也称内存栅栏,内存栅障,屏障指令等,是一类同步屏障指令,
\n 它使得 CPU 或编译器在对内存进行操作的时候, 严格按照一定的顺序来执行, 也就是说在memory barrier 之前的指令
\n 和memory barrier之后的指令不会由于系统优化等原因而导致乱序。
\n 大多数现代计算机为了提高性能而采取乱序执行,这使得内存屏障成为必须。
\n 大多数现代计算机为了提高性能而采取乱序执行,这使得内存屏障成为必须。
\n 语义上,内存屏障之前的所有写操作都要写入内存;内存屏障之后的读操作都可以获得同步屏障之前的写操作的结果。
\n 因此,对于敏感的程序块,写操作之后、读操作之前可以插入内存屏障。
*
* @param index
* @return
*
* @see
*/
*
* @param index
* @return
*
* @see
*/
// https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/memory-access-ordering---an-introduction
......
此差异已折叠。
......@@ -323,15 +323,15 @@ STATIC INLINE BOOL OsProcessIsUserMode(const LosProcessCB *processCB)
#define LOS_SCHED_NORMAL 0U ///< 正常调度
#define LOS_SCHED_FIFO 1U ///< 先进先出,按顺序
#define LOS_SCHED_RR 2U ///< 抢占式调度
#define LOS_SCHED_IDLE 3U
#define LOS_SCHED_RR 2U ///< 抢占式调度,鸿蒙默认调度方式
#define LOS_SCHED_IDLE 3U ///< 空闲不调度
#define LOS_PRIO_PROCESS 0U ///< 进程标识
#define LOS_PRIO_PGRP 1U ///< 进程组标识
#define LOS_PRIO_USER 2U ///< 用户标识
#define OS_USER_PRIVILEGE_PROCESS_GROUP 1U
#define OS_KERNEL_PROCESS_GROUP 2U
#define OS_USER_PRIVILEGE_PROCESS_GROUP 1U ///< 用户态进程组ID
#define OS_KERNEL_PROCESS_GROUP 2U ///< 内核态进程组ID
/*
* Process exit code
......
......@@ -59,10 +59,10 @@ extern "C" {
*
* Task siginal types.
*/
#define SIGNAL_NONE 0U //无信号
#define SIGNAL_KILL (1U << 0) //干掉
#define SIGNAL_SUSPEND (1U << 1) //挂起
#define SIGNAL_AFFI (1U << 2) //CPU 亲和性,一个任务被切换后被同一个CPU再次执行,则亲和力高
#define SIGNAL_NONE 0U ///< 无信号
#define SIGNAL_KILL (1U << 0) ///< 干掉
#define SIGNAL_SUSPEND (1U << 1) ///< 挂起
#define SIGNAL_AFFI (1U << 2) ///< CPU 亲和性,一个任务被切换后被同一个CPU再次执行,则亲和力高
/* scheduler lock */
extern SPIN_LOCK_S g_taskSpin;//任务自旋锁
......@@ -286,8 +286,8 @@ extern SPIN_LOCK_S g_taskSpin;//任务自旋锁
* @par Dependency:
* <ul><li>los_task_pri.h: the header file that contains the API declaration.</li></ul>
* @see
*/ ///通过任务ID找到任务实体
#define OS_TCB_FROM_TID(taskID) (((LosTaskCB *)g_taskCBArray) + (taskID))
*/
#define OS_TCB_FROM_TID(taskID) (((LosTaskCB *)g_taskCBArray) + (taskID)) ///< 通过任务ID从任务池中拿到实体
#ifndef LOSCFG_STACK_POINT_ALIGN_SIZE
#define LOSCFG_STACK_POINT_ALIGN_SIZE (sizeof(UINTPTR) * 2)
......@@ -304,7 +304,7 @@ typedef struct {
VOID *stackPointer; /**< Task stack pointer | 内核栈指针位置(SP) */
UINT16 taskStatus; /**< Task status | 各种状态标签,可以拥有多种标签,按位标识 */
UINT16 priority; /**< Task priority | 任务优先级[0:31],默认是31级 */
UINT16 policy; ///< 任务的调度方式(三种 .. LOS_SCHED_RR )
UINT16 policy; ///< 任务的调度方式(三种 .. LOS_SCHED_RR LOS_SCHED_FIFO .. )
UINT64 startTime; /**< The start time of each phase of task | 任务开始时间 */
UINT64 irqStartTime; /**< Interrupt start time | 任务中断开始时间 */
UINT32 irqUsedTime; /**< Interrupt consumption time | 任务中断恢复时间 */
......@@ -337,8 +337,8 @@ typedef struct {
UINT16 currCpu; /**< CPU core number of this task is running on | 正在运行此任务的CPU内核号 */
UINT16 lastCpu; /**< CPU core number of this task is running on last time | 上次运行此任务的CPU内核号 */
UINT16 cpuAffiMask; /**< CPU affinity mask, support up to 16 cores | CPU亲和力掩码,最多支持16核,亲和力很重要,多核情况下尽量一个任务在一个CPU核上运行,提高效率 */
#ifdef LOSCFG_KERNEL_SMP_TASK_SYNC
UINT32 syncSignal; /**< Synchronization for signal handling | 用于CPU之间 同步信号 */
#ifdef LOSCFG_KERNEL_SMP_TASK_SYNC //多核情况下的任务同步开关,采用信号量实现
UINT32 syncSignal; /**< Synchronization for signal handling | 用于CPU之间同步信号量 */
#endif
#ifdef LOSCFG_KERNEL_SMP_LOCKDEP //SMP死锁检测开关
LockDep lockDep; ///< 死锁依赖检测
......@@ -357,8 +357,8 @@ typedef struct {
UINTPTR waitID; /**< Wait for the PID or GID of the child process | */
UINT16 waitFlag; /**< The type of child process that is waiting, belonging to a group or parent,
a specific child process, or any child process | 以什么样的方式等待子进程结束(OS_TASK_WAIT_PROCESS | OS_TASK_WAIT_GID | ..) */
#ifdef LOSCFG_KERNEL_LITEIPC
IpcTaskInfo *ipcTaskInfo; ///< 任务IPC信息结构体
#ifdef LOSCFG_KERNEL_LITEIPC //轻量级进程间通信开关
IpcTaskInfo *ipcTaskInfo; ///< 任务间通讯信息结构体
#endif
#ifdef LOSCFG_KERNEL_PERF
UINTPTR pc; ///< pc寄存器
......@@ -380,7 +380,7 @@ struct ProcessSignalInfo {
LosTaskCB *receivedTcb; /**< This TCB received the signal | 如果没有屏蔽信号,任务将接收这个信号. */
};
typedef int (*ForEachTaskCB)(LosTaskCB *tcb, void *arg);//回调任务函数,例如:进程被kill 9 时,通知所有任务善后处理
typedef int (*ForEachTaskCB)(LosTaskCB *tcb, void *arg);///< 回调任务函数,例如:进程被kill 9 时,通知所有任务善后处理
/**
* @ingroup los_task
......@@ -476,19 +476,19 @@ STATIC INLINE BOOL OsTaskIsKilled(const LosTaskCB *taskCB)
/* get task info */
#define OS_ALL_TASK_MASK 0xFFFFFFFF
#define OS_TASK_WAIT_ANYPROCESS (1 << 0U) ///< 任务等待任何进程出现
#define OS_TASK_WAIT_PROCESS (1 << 1U) ///< 任务等待进程出现
#define OS_TASK_WAIT_GID (1 << 2U) ///< 任务等待组ID
#define OS_TASK_WAIT_SEM (OS_TASK_WAIT_GID + 1) ///< 任务等待信号量发生
#define OS_TASK_WAIT_QUEUE (OS_TASK_WAIT_SEM + 1) ///< 任务等待队列到来
#define OS_TASK_WAIT_JOIN (OS_TASK_WAIT_QUEUE + 1) ///< 任务等待
#define OS_TASK_WAIT_SIGNAL (OS_TASK_WAIT_JOIN + 1) ///< 任务等待信号的到来
#define OS_TASK_WAIT_LITEIPC (OS_TASK_WAIT_SIGNAL + 1) ///< 任务等待liteipc到来
#define OS_TASK_WAIT_MUTEX (OS_TASK_WAIT_LITEIPC + 1) ///< 任务等待MUTEX到来
#define OS_TASK_WAIT_FUTEX (OS_TASK_WAIT_MUTEX + 1) ///< 任务等待FUTEX到来
#define OS_TASK_WAIT_EVENT (OS_TASK_WAIT_FUTEX + 1) ///< 任务等待事件发生
#define OS_TASK_WAIT_COMPLETE (OS_TASK_WAIT_EVENT + 1) ///< 任务等待完成
/// 任务的信号列表
#define OS_TASK_WAIT_ANYPROCESS (1 << 0U) ///< 等待任意进程出现
#define OS_TASK_WAIT_PROCESS (1 << 1U) ///< 等待指定进程出现
#define OS_TASK_WAIT_GID (1 << 2U) ///< 等待组ID
#define OS_TASK_WAIT_SEM (OS_TASK_WAIT_GID + 1) ///< 等待信号量发生
#define OS_TASK_WAIT_QUEUE (OS_TASK_WAIT_SEM + 1) ///< 等待队列到来
#define OS_TASK_WAIT_JOIN (OS_TASK_WAIT_QUEUE + 1) ///< 等待
#define OS_TASK_WAIT_SIGNAL (OS_TASK_WAIT_JOIN + 1) ///<
#define OS_TASK_WAIT_LITEIPC (OS_TASK_WAIT_SIGNAL + 1) ///< 等待liteipc到来
#define OS_TASK_WAIT_MUTEX (OS_TASK_WAIT_LITEIPC + 1) ///< 等待MUTEX到来
#define OS_TASK_WAIT_FUTEX (OS_TASK_WAIT_MUTEX + 1) ///< 等待FUTEX到来
#define OS_TASK_WAIT_EVENT (OS_TASK_WAIT_FUTEX + 1) ///< 等待事件发生
#define OS_TASK_WAIT_COMPLETE (OS_TASK_WAIT_EVENT + 1) ///< 等待结束信号
/// 设置事件阻塞掩码,即设置任务的等待事件.
STATIC INLINE VOID OsTaskWaitSetPendMask(UINT16 mask, UINTPTR lockID, UINT32 timeout)
......
......@@ -172,7 +172,7 @@ LITE_OS_SEC_TEXT STATIC UINT32 OsEventReadCheck(const PEVENT_CB_S eventCB, UINT3
}
return LOS_OK;
}
///读取指定事件类型的实现函数,超时时间为相对时间:单位为Tick
/// 读取指定事件类型的实现函数,超时时间为相对时间:单位为Tick
LITE_OS_SEC_TEXT STATIC UINT32 OsEventReadImp(PEVENT_CB_S eventCB, UINT32 eventMask, UINT32 mode,
UINT32 timeout, BOOL once)
{
......@@ -196,8 +196,8 @@ LITE_OS_SEC_TEXT STATIC UINT32 OsEventReadImp(PEVENT_CB_S eventCB, UINT32 eventM
runTask->eventMask = eventMask; //等待事件
runTask->eventMode = mode; //事件模式
runTask->taskEvent = eventCB; //事件控制块
OsTaskWaitSetPendMask(OS_TASK_WAIT_EVENT, eventMask, timeout);
ret = OsSchedTaskWait(&eventCB->stEventList, timeout, TRUE);
OsTaskWaitSetPendMask(OS_TASK_WAIT_EVENT, eventMask, timeout);//任务进入等待状态,等待事件的到来并设置时长和掩码
ret = OsSchedTaskWait(&eventCB->stEventList, timeout, TRUE);//任务暂停,切换调度.
if (ret == LOS_ERRNO_TSK_TIMEOUT) {
return LOS_ERRNO_EVENT_READ_TIMEOUT;
}
......
......@@ -139,14 +139,14 @@ STATIC INLINE VOID OsSigWaitTaskWake(LosTaskCB *taskCB, INT32 signo)
OsSigEmptySet(&sigcb->sigwaitmask);
}
}
///< 唤醒被挂起的处于等待指定信号的任务
STATIC UINT32 OsPendingTaskWake(LosTaskCB *taskCB, INT32 signo)
{
if (!OsTaskIsPending(taskCB) || !OsProcessIsUserMode(OS_PCB_FROM_PID(taskCB->processID))) {
return 0;
}
if ((signo != SIGKILL) && (taskCB->waitFlag != OS_TASK_WAIT_SIGNAL)) {
if ((signo != SIGKILL) && (taskCB->waitFlag != OS_TASK_WAIT_SIGNAL)) { // @note_thinking 这个判断会不会有问题 ?
return 0;
}
......@@ -760,7 +760,7 @@ VOID *OsSaveSignalContext(VOID *sp, VOID *newSp)
OsProcessExitCodeSignalSet(process, signo);
sigcb->sigContext = sp;
OsInitSignalContext(sp, newSp, sigHandler, signo, sigVal);
OsInitSignalContext(sp, newSp, sigHandler, signo, sigVal);//初始化信号上下文
/* sig No bits 00000100 present sig No 3, but 1<< 3 = 00001000, so signo needs minus 1 */
sigcb->sigFlag ^= 1ULL << (signo - 1);
......
/*!
* @file hm_liteipc.c
* @brief 轻量级进程间通信
* @link LiteIPC http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-small-bundles-ipc.html @endlink
@verbatim
基本概念
LiteIPC是OpenHarmony LiteOS-A内核提供的一种新型IPC(Inter-Process Communication,即进程间通信)机制,
不同于传统的System V IPC机制,LiteIPC主要是为RPC(Remote Procedure Call,即远程过程调用)而设计的,
而且是通过设备文件的方式对上层提供接口的,而非传统的API函数方式。
LiteIPC中有两个主要概念,一个是ServiceManager,另一个是Service。整个系统只能有一个ServiceManager,
而Service可以有多个。ServiceManager有两个主要功能:一是负责Service的注册和注销,二是负责管理Service的
访问权限(只有有权限的任务(Task)可以向对应的Service发送IPC消息)。
运行机制
首先将需要接收IPC消息的任务通过ServiceManager注册成为一个Service,然后通过ServiceManager为该Service
任务配置访问权限,即指定哪些任务可以向该Service任务发送IPC消息。LiteIPC的核心思想就是在内核态为
每个Service任务维护一个IPC消息队列,该消息队列通过LiteIPC设备文件向上层用户态程序分别提供代表收取
IPC消息的读操作和代表发送IPC消息的写操作。
@endverbatim
* @version
* @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
* @date 2021-11-22
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
......@@ -46,33 +70,33 @@
#include "los_vm_phys.h"
#include "los_hook.h"
#define USE_TASKID_AS_HANDLE YES //使用任务ID作为句柄
#define USE_TASKID_AS_HANDLE YES ///< 使用任务ID作为句柄
#define USE_MMAP YES //
#define IPC_IO_DATA_MAX 8192UL //最大的消息内容 8K ,posix最大消息内容 64个字节
#define IPC_IO_DATA_MAX 8192UL ///< 最大的消息内容 8K ,posix最大消息内容 64个字节
#define IPC_MSG_DATA_SZ_MAX (IPC_IO_DATA_MAX * sizeof(SpecialObj) / (sizeof(SpecialObj) + sizeof(size_t)))
#define IPC_MSG_OBJECT_NUM_MAX (IPC_MSG_DATA_SZ_MAX / sizeof(SpecialObj))
#define IPC_MSG_OBJECT_NUM_MAX (IPC_MSG_DATA_SZ_MAX / sizeof(SpecialObj))
#define LITE_IPC_POOL_NAME "liteipc" //ipc池名称
#define LITE_IPC_POOL_NAME "liteipc" ///< ipc池名称
#define LITE_IPC_POOL_PAGE_MAX_NUM 64 /* 256KB */
#define LITE_IPC_POOL_PAGE_DEFAULT_NUM 16 /* 64KB */
#define LITE_IPC_POOL_MAX_SIZE (LITE_IPC_POOL_PAGE_MAX_NUM << PAGE_SHIFT) //最大IPC池 256K
#define LITE_IPC_POOL_DEFAULT_SIZE (LITE_IPC_POOL_PAGE_DEFAULT_NUM << PAGE_SHIFT)//默认IPC池 64K
#define LITE_IPC_POOL_MAX_SIZE (LITE_IPC_POOL_PAGE_MAX_NUM << PAGE_SHIFT) ///< 最大IPC池 256K
#define LITE_IPC_POOL_DEFAULT_SIZE (LITE_IPC_POOL_PAGE_DEFAULT_NUM << PAGE_SHIFT)///< 默认IPC池 64K
#define LITE_IPC_POOL_UVADDR 0x10000000
#define INVAILD_ID (-1)
#define LITEIPC_TIMEOUT_MS 5000UL //超时时间单位毫秒
#define LITEIPC_TIMEOUT_NS 5000000000ULL //超时时间单位纳秒
#define LITEIPC_TIMEOUT_MS 5000UL ///< 超时时间单位毫秒
#define LITEIPC_TIMEOUT_NS 5000000000ULL ///< 超时时间单位纳秒
typedef struct {//IPC使用节点
LOS_DL_LIST list;//通过它挂到对应g_ipcUsedNodelist[processID]上
LOS_DL_LIST list;///< 通过它挂到对应g_ipcUsedNodelist[processID]上
VOID *ptr;
} IpcUsedNode;
STATIC LosMux g_serviceHandleMapMux;
#if (USE_TASKID_AS_HANDLE == YES)// @note_why 前缀cms是何意思? 猜测是Content Management System(内容管理系统)
#if (USE_TASKID_AS_HANDLE == YES) // @note_why 前缀cms是何意思? 猜测是Content Management System(内容管理系统) :(
STATIC HandleInfo g_cmsTask;
#else
STATIC HandleInfo g_serviceHandleMap[MAX_SERVICE_NUM];
STATIC HandleInfo g_serviceHandleMap[MAX_SERVICE_NUM]; ///< 整个系统只能有一个 ServiceManager 用于管理 service
#endif
STATIC LOS_DL_LIST g_ipcPendlist;//阻塞链表,上面挂等待读/写消息的任务LosTaskCB
......@@ -97,13 +121,20 @@ STATIC const struct file_operations_vfs g_liteIpcFops = {
.mmap = LiteIpcMmap, /* mmap */
};
/*!
* @brief OsLiteIpcInit 初始化LiteIPC模块
*
* @return
*
* @see
*/
LITE_OS_SEC_TEXT_INIT UINT32 OsLiteIpcInit(VOID)
{
UINT32 ret;
#if (USE_TASKID_AS_HANDLE == YES)
g_cmsTask.status = HANDLE_NOT_USED;
#if (USE_TASKID_AS_HANDLE == YES) //两种管理方式,一种是 任务ID == service ID
g_cmsTask.status = HANDLE_NOT_USED;//默认未使用
#else
memset_s(g_serviceHandleMap, sizeof(g_serviceHandleMap), 0, sizeof(g_serviceHandleMap));
memset_s(g_serviceHandleMap, sizeof(g_serviceHandleMap), 0, sizeof(g_serviceHandleMap));//默认未使用
#endif
ret = LOS_MuxInit(&g_serviceHandleMapMux, NULL);
if (ret != LOS_OK) {
......@@ -243,7 +274,7 @@ ERROR_REGION_OUT:
ipcInfo->pool.kvaddr = NULL;
return ret;
}
///ipc内存池初始化
///初始化进程的IPC消息内存池
LITE_OS_SEC_TEXT_INIT STATIC UINT32 LiteIpcPoolInit(ProcIpcInfo *ipcInfo)
{
ipcInfo->pool.uvaddr = NULL;
......@@ -253,7 +284,7 @@ LITE_OS_SEC_TEXT_INIT STATIC UINT32 LiteIpcPoolInit(ProcIpcInfo *ipcInfo)
LOS_ListInit(&ipcInfo->ipcUsedNodelist);
return LOS_OK;
}
///创建OPC消息内存池
LITE_OS_SEC_TEXT_INIT STATIC ProcIpcInfo *LiteIpcPoolCreate(VOID)
{
ProcIpcInfo *ipcInfo = LOS_MemAlloc(m_aucSysMem1, sizeof(ProcIpcInfo));
......@@ -266,7 +297,7 @@ LITE_OS_SEC_TEXT_INIT STATIC ProcIpcInfo *LiteIpcPoolCreate(VOID)
(VOID)LiteIpcPoolInit(ipcInfo);
return ipcInfo;
}
/// 重新初始化进程的IPC消息内存池
LITE_OS_SEC_TEXT ProcIpcInfo *LiteIpcPoolReInit(const ProcIpcInfo *parent)
{
ProcIpcInfo *ipcInfo = LiteIpcPoolCreate();
......@@ -280,7 +311,7 @@ LITE_OS_SEC_TEXT ProcIpcInfo *LiteIpcPoolReInit(const ProcIpcInfo *parent)
ipcInfo->ipcTaskID = INVAILD_ID;
return ipcInfo;
}
/// 释放进程的IPC消息内存池
STATIC VOID LiteIpcPoolDelete(ProcIpcInfo *ipcInfo, UINT32 processID)
{
UINT32 intSave;
......@@ -320,7 +351,7 @@ LITE_OS_SEC_TEXT UINT32 LiteIpcPoolDestroy(UINT32 processID)
pcb->ipcInfo = NULL;
return LOS_OK;
}
/// 申请并初始化一个任务IPC
LITE_OS_SEC_TEXT_INIT STATIC IpcTaskInfo *LiteIpcTaskInit(VOID)
{
IpcTaskInfo *taskInfo = LOS_MemAlloc((VOID *)m_aucSysMem1, sizeof(IpcTaskInfo));
......@@ -332,7 +363,7 @@ LITE_OS_SEC_TEXT_INIT STATIC IpcTaskInfo *LiteIpcTaskInit(VOID)
LOS_ListInit(&taskInfo->msgListHead);
return taskInfo;
}
///只有当内核不再访问ipc节点内容时,用户才能释放ipc节点
/// 只有当内核不再访问ipc节点内容时,用户才能释放ipc节点
/* Only when kernel no longer access ipc node content, can user free the ipc node */
LITE_OS_SEC_TEXT STATIC VOID EnableIpcNodeFreeByUser(UINT32 processID, VOID *buf)//用户释放一个在使用的IPC节点
{
......@@ -342,11 +373,11 @@ LITE_OS_SEC_TEXT STATIC VOID EnableIpcNodeFreeByUser(UINT32 processID, VOID *buf
if (node != NULL) {
node->ptr = buf;
IPC_LOCK(intSave);
LOS_ListAdd(&ipcInfo->ipcUsedNodelist, &node->list);
LOS_ListAdd(&ipcInfo->ipcUsedNodelist, &node->list);//
IPC_UNLOCK(intSave);
}
}
///分配一个IPC节点
///从内核对内存中分配一个IPC节点
LITE_OS_SEC_TEXT STATIC VOID *LiteIpcNodeAlloc(UINT32 processID, UINT32 size)
{
VOID *ptr = LOS_MemAlloc(OS_PCB_FROM_PID(processID)->ipcInfo->pool.kvaddr, size);
......@@ -410,7 +441,7 @@ LITE_OS_SEC_TEXT STATIC UINT32 CheckUsedBuffer(const VOID *node, IpcListNode **o
*outPtr = (IpcListNode *)ptr;
return LOS_OK;
}
/// 获取任务ID
LITE_OS_SEC_TEXT STATIC UINT32 GetTid(UINT32 serviceHandle, UINT32 *taskID)
{
if (serviceHandle >= MAX_SERVICE_NUM) {
......@@ -422,8 +453,8 @@ LITE_OS_SEC_TEXT STATIC UINT32 GetTid(UINT32 serviceHandle, UINT32 *taskID)
(VOID)LOS_MuxUnlock(&g_serviceHandleMapMux);
return LOS_OK;
#else
if (g_serviceHandleMap[serviceHandle].status == HANDLE_REGISTED) {
*taskID = g_serviceHandleMap[serviceHandle].taskID;
if (g_serviceHandleMap[serviceHandle].status == HANDLE_REGISTED) {//必须得是已注册
*taskID = g_serviceHandleMap[serviceHandle].taskID;//获取已注册服务的任务ID
(VOID)LOS_MuxUnlock(&g_serviceHandleMapMux);
return LOS_OK;
}
......@@ -469,10 +500,19 @@ LITE_OS_SEC_TEXT STATIC VOID RefreshServiceHandle(UINT32 serviceHandle, UINT32 r
#endif
}
/*!
* @brief AddServiceAccess 配置访问权限
*
* @param serviceHandle
* @param taskID
* @return
*
* @see
*/
LITE_OS_SEC_TEXT STATIC UINT32 AddServiceAccess(UINT32 taskID, UINT32 serviceHandle)
{
UINT32 serviceTid = 0;
UINT32 ret = GetTid(serviceHandle, &serviceTid);
UINT32 ret = GetTid(serviceHandle, &serviceTid);//通过服务获取所在任务
if (ret != LOS_OK) {
PRINT_ERR("Liteipc AddServiceAccess GetTid failed\n");
return ret;
......@@ -484,15 +524,15 @@ LITE_OS_SEC_TEXT STATIC UINT32 AddServiceAccess(UINT32 taskID, UINT32 serviceHan
PRINT_ERR("Liteipc AddServiceAccess ipc not create! pid %u tid %u\n", processID, tcb->taskID);
return -EINVAL;
}
tcb->ipcTaskInfo->accessMap[processID] = TRUE;
tcb->ipcTaskInfo->accessMap[processID] = TRUE;//允许任务给自己所属进程发送IPC消息
pcb->ipcInfo->access[serviceTid] = TRUE;
return LOS_OK;
}
/// 参数服务是否有访问当前进程的权限,实际中会有 A进程的任务去给B进程发送IPC信息,所以需要鉴权
LITE_OS_SEC_TEXT STATIC BOOL HasServiceAccess(UINT32 serviceHandle)
{
UINT32 serviceTid = 0;
UINT32 curProcessID = LOS_GetCurrProcessID();
UINT32 curProcessID = LOS_GetCurrProcessID();//获取当前进程ID
UINT32 ret;
if (serviceHandle >= MAX_SERVICE_NUM) {
return FALSE;
......@@ -500,12 +540,12 @@ LITE_OS_SEC_TEXT STATIC BOOL HasServiceAccess(UINT32 serviceHandle)
if (serviceHandle == 0) {
return TRUE;
}
ret = GetTid(serviceHandle, &serviceTid);
ret = GetTid(serviceHandle, &serviceTid);//获取参数服务所属任务ID
if (ret != LOS_OK) {
PRINT_ERR("Liteipc HasServiceAccess GetTid failed\n");
return FALSE;
}
if (OS_TCB_FROM_TID(serviceTid)->processID == curProcessID) {
if (OS_TCB_FROM_TID(serviceTid)->processID == curProcessID) {//如果任务所在进程就是当前进程,直接返回OK
return TRUE;
}
......@@ -533,7 +573,7 @@ LITE_OS_SEC_TEXT BOOL IsIpcTaskSet(VOID)
}
return TRUE;
}
///获取
/// 获取IPC任务ID
LITE_OS_SEC_TEXT STATIC UINT32 GetIpcTaskID(UINT32 processID, UINT32 *ipcTaskID)
{
if (OS_PCB_FROM_PID(processID)->ipcInfo->ipcTaskID == INVAILD_ID) {
......@@ -542,7 +582,7 @@ LITE_OS_SEC_TEXT STATIC UINT32 GetIpcTaskID(UINT32 processID, UINT32 *ipcTaskID)
*ipcTaskID = OS_PCB_FROM_PID(processID)->ipcInfo->ipcTaskID;
return LOS_OK;
}
///发送死亡消息
/// 发送死亡消息
LITE_OS_SEC_TEXT STATIC UINT32 SendDeathMsg(UINT32 processID, UINT32 serviceHandle)
{
UINT32 ipcTaskID;
......@@ -570,7 +610,7 @@ LITE_OS_SEC_TEXT STATIC UINT32 SendDeathMsg(UINT32 processID, UINT32 serviceHand
content.outMsg->code = 0;
return LiteIpcWrite(&content);
}
/// 删除指定的Service
LITE_OS_SEC_TEXT VOID LiteIpcRemoveServiceHandle(UINT32 taskID)
{
UINT32 j;
......@@ -773,16 +813,16 @@ LITE_OS_SEC_TEXT STATIC UINT32 HandleSvc(UINT32 dstTid, const SpecialObj *obj, B
}
return LOS_OK;
}
/// 创建处理对象
LITE_OS_SEC_TEXT STATIC UINT32 HandleObj(UINT32 dstTid, SpecialObj *obj, BOOL isRollback)
{
UINT32 ret;
UINT32 processID = OS_TCB_FROM_TID(dstTid)->processID;
UINT32 processID = OS_TCB_FROM_TID(dstTid)->processID;//获取目标任务所在进程
switch (obj->type) {
case OBJ_FD:
case OBJ_FD://fd:文件描述符
ret = HandleFd(processID, obj, isRollback);
break;
case OBJ_PTR:
case OBJ_PTR://指针
ret = HandlePtr(processID, obj, isRollback);
break;
case OBJ_SVC:
......
......@@ -50,10 +50,10 @@ extern "C" {
句柄是给用户程序使用的一个数字凭证,能以小博大,通过柄
能牵动内核模块工作.
*/
#define LITEIPC_DRIVER "/dev/lite_ipc" ///< 设备位置
#define LITEIPC_DRIVER_MODE 0644
#define LITEIPC_DRIVER "/dev/lite_ipc" ///< 虚拟设备
#define LITEIPC_DRIVER_MODE 0644 ///< 对虚拟设备的访问权限 110100100 表示只有所属用户才有读写权限,其余都只能读
#define MAX_SERVICE_NUM LOSCFG_BASE_CORE_TSK_LIMIT ///< 最大服务数等于任务数 默认128
#define USE_TIMESTAMP YES
#define USE_TIMESTAMP YES ///< 使用时间戳
/**
* @enum HandleStatus
......@@ -90,14 +90,15 @@ typedef struct {
* @brief 进程IPC信息,见于进程结构体: LosProcessCB.ipcInfo
*/
typedef struct {
IpcPool pool; ///< ipc池
UINT32 ipcTaskID; //ipc任务ID
LOS_DL_LIST ipcUsedNodelist;
IpcPool pool; ///< ipc池
UINT32 ipcTaskID; ///< ipc任务ID
LOS_DL_LIST ipcUsedNodelist;///< 已使用节点链表
UINT32 access[LOSCFG_BASE_CORE_TSK_LIMIT]; ///< 访问的任务数组
} ProcIpcInfo;
typedef struct {
LOS_DL_LIST msgListHead;
BOOL accessMap[LOSCFG_BASE_CORE_TSK_LIMIT];
LOS_DL_LIST msgListHead;///< 上面挂的是一个个的 ipc节点
BOOL accessMap[LOSCFG_BASE_CORE_TSK_LIMIT]; ///< 此处是不是应该用 LOSCFG_BASE_CORE_PROCESS_LIMIT ? @note_thinking
///< 任务是否可以给其他进程发送IPC消息
} IpcTaskInfo;
typedef enum {
......@@ -110,22 +111,22 @@ typedef struct {
UINT32 buffSz;
VOID *buff;
} BuffPtr;
/// svc 是啥哩? @note_thinking
typedef struct {
UINT32 handle;
UINT32 handle;
UINT32 token;
UINT32 cookie;
} SvcIdentity;
/// 对象内容体
typedef union {
UINT32 fd;
BuffPtr ptr;
UINT32 fd; ///< 文件描述符
BuffPtr ptr;///< 缓存的开始地址,即:指针
SvcIdentity svc;
} ObjContent;
/// 特殊对象
typedef struct {
ObjType type;
ObjContent content;
ObjType type; ///< 类型
ObjContent content;///< 内容
} SpecialObj;
/**
......@@ -184,8 +185,8 @@ typedef struct {
} IpcMsg;
typedef struct { //IPC 内容节点
IpcMsg msg; //内容体
LOS_DL_LIST listNode;//通过它挂到LosTaskCB.msgListHead链表上
IpcMsg msg; ///< 内容体
LOS_DL_LIST listNode; ///< 通过它挂到LosTaskCB.msgListHead链表上
} IpcListNode;
#define SEND (1 << 0) ///< 发送
......
......@@ -61,12 +61,12 @@ typedef struct {
} TELNTE_FIFO_S;
//远程登录设备结构体
typedef struct {
INT32 clientFd;
UINT32 id;
BOOL eventPend;
EVENT_CB_S eventTelnet;
INT32 clientFd; ///< 客户端文件句柄
UINT32 id;
BOOL eventPend; ///< 事件是否挂起
EVENT_CB_S eventTelnet; ///< 远程登录事件
wait_queue_head_t wait;
TELNTE_FIFO_S *cmdFifo; /* use a FIFO to store user's commands */
TELNTE_FIFO_S *cmdFifo; /* use a FIFO to store user's commands | 使用先进先出保存用户的命令*/
} TELNET_DEV_S;
extern INT32 TelnetTx(const CHAR *buf, UINT32 len);
......
......@@ -50,8 +50,8 @@
#include "fs/driver.h"
/* event: there are more commands left in the FIFO to run */
#define TELNET_EVENT_MORE_CMD 0x01
#define TELNET_DEV_DRV_MODE 0666
#define TELNET_EVENT_MORE_CMD 0x01 ///< 还有很多命令在FIFO中等待运行的事件
#define TELNET_DEV_DRV_MODE 0666 ///< 文件权限 chmod = 666
STATIC TELNET_DEV_S g_telnetDev;
STATIC EVENT_CB_S *g_event;
......@@ -193,6 +193,7 @@ STATIC INT32 TelnetClose(struct file *file)
/*
* Description : When a command resolver task trys to read the telnet device,
* this method is called, and it will take out user's commands from the FIFO to run.
* 当命令解析器任务尝试读取 telnet 设备时,调用这个方法,它会从FIFO中取出用户的命令来运行。
* Return : -1 --- On failure
* Non-negative integer --- length of commands taken out from the FIFO of the telnet device.
*/
......@@ -203,15 +204,15 @@ STATIC ssize_t TelnetRead(struct file *file, CHAR *buf, size_t bufLen)
TelnetLock();
telnetDev = GetTelnetDevByFile(file, FALSE);
telnetDev = GetTelnetDevByFile(file, FALSE);//获取远程登录实体
if ((buf == NULL) || (telnetDev == NULL) || (telnetDev->cmdFifo == NULL)) {
TelnetUnlock();
return -1;
}
if (telnetDev->eventPend) {
if (telnetDev->eventPend) {//挂起时,读取
TelnetUnlock();
(VOID)LOS_EventRead(g_event, TELNET_EVENT_MORE_CMD, LOS_WAITMODE_OR, LOS_WAIT_FOREVER);
(VOID)LOS_EventRead(g_event, TELNET_EVENT_MORE_CMD, LOS_WAITMODE_OR, LOS_WAIT_FOREVER);//等待读取 TELNET_EVENT_MORE_CMD 事件
TelnetLock();
}
......@@ -351,7 +352,7 @@ INT32 TelnetedUnregister(VOID)
{
free(g_telnetDev.cmdFifo);
g_telnetDev.cmdFifo = NULL;
(VOID)unregister_driver(TELNET);
(VOID)unregister_driver(TELNET);//注销字符设备驱动
return 0;
}
......@@ -394,7 +395,8 @@ INT32 TelnetDevInit(INT32 clientFd)
return ret;
}
/* When closing the telnet client connection, reset the output console for tasks. */
/* When closing the telnet client connection, reset the output console for tasks. |
关闭 telnet 客户端连接时,重置任务的控制台信息。*/
INT32 TelnetDevDeinit(VOID)
{
INT32 ret;
......
/*!
* @file telnet_loop.c
* @brief
* @link
* @file telnet_loop.c
* @brief telnet实现过程
* @link RFC854 https://docs.huihoo.com/rfc/RFC854.txt @endlink
@verbatim
telnet命令通常用来远程登录。telnet程序是基于TELNET协议的远程登录客户端程序。Telnet协议是TCP/IP协议族中的一员,
是Internet远程登陆服务的标准协议和主要方式。它为用户提供了在本地计算机上完成远程主机工作的 能力。
......@@ -13,7 +13,41 @@
但仍然有很多别的系统可能采用了telnet方式来提供远程登录,因此弄清楚telnet客户端的使用方式仍是很有必要的。
telnet命令还可做别的用途,比如确定远程服务的状态,比如确定远程服务器的某个端口是否能访问。
下面几个编码对NVT打印机有确定意义:
名称 编码 意义
NULL (NUL) 0 没有操作
BELL (BEL) 7 产生一个可以看到或可以听到的信号(而不移动打印头。)
Back Space (BS) 8 向左移动打印头一个字符位置。
Horizontal Tab (HT) 9 把打印头移到下一个水平制表符停止的位置。它仍然没有指定每一方如何检测或者设定如何定位这样的制表符的停止位置。
Line Feed (LF) 10 打印头移到下一个打印行,但不改变打印头的水平位置。
Vertical Tab (VT) 11 把打印头移到下一个垂直制表符停止的位置。它仍然没有指定每一方如何检测或者设定如何定位这样的制表符的停止位置。
Form Feed (FF) 12 把打印头移到下一页的顶部,保持打印头在相同的水平位置上。
Carriage Return (CR) 13 把打印头移到当前行的左边 。
下面是所有已定义的TELNET命令。需要注意的是,这些代码和代码序列只有在前面跟一个IAC时才有意义。
------------------------------------------------------------------------
名称 代码 意义
------------------------------------------------------------------------
SE 240 子谈判参数的结束
NOP 241 空操作
Data Mark 242 一个同步信号的数据流部分。该命令的后面经常跟着一个TCP紧急通知
Break 243 NVT的BRK字符
Interrupt Process 244 IP功能.
Abort output 245 AO功能.
Are You There 246 AYT功能.
Erase character 247 EC功能.
Erase Line 248 EL功能.
Go ahead 249 GA信号.
SB 250 表示后面所跟的是对需要的选项的子谈判
WILL (option code) 251 表示希望开始使用或者确认所使用的是指定的选项。
WON'T (option code) 252 表示拒绝使用或者继续使用指定的选项。
DO (option code) 253 表示一方要求另一方使用,或者确认你希望另一方使用指定的选项。
DON'T (option code) 254 表示一方要求另一方停止使用,或者确认你不再希望另一方使用指定的选项。
IAC 255 Data Byte 255.
@endverbatim
* @version
* @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
......@@ -76,15 +110,18 @@
/* TELNET commands in RFC854 */
#define TELNET_SB 250 /* Indicates that what follows is subnegotiation of the indicated option */
#define TELNET_WILL 251 /* Indicates the desire to perform the indicated option */
#define TELNET_DO 253 /* Indicates the request for the other party to perform the indicated option */
#define TELNET_IAC 255 /* Interpret as Command */
#define TELNET_SB 250 /* Indicates that what follows is subnegotiation of the indicated option
| 表示后面所跟的是对需要的选项的子谈判*/
#define TELNET_WILL 251 /* Indicates the desire to perform the indicated option
| 表示希望执行指定的选项*/
#define TELNET_DO 253 /* Indicates the request for the other party to perform the indicated option
| 表示一方要求另一方使用,或者确认你希望另一方使用指定的选项。*/
#define TELNET_IAC 255 /* Interpret as Command | 中断命令*/
/* telnet options in IANA */
#define TELNET_ECHO 1 /* Echo */
#define TELNET_SGA 3 /* Suppress Go Ahead */
#define TELNET_NAWS 31 /* Negotiate About Window Size */
#define TELNET_ECHO 1 /* Echo | 回显*/
#define TELNET_SGA 3 /* Suppress Go Ahead | 抑制继续进行*/
#define TELNET_NAWS 31 /* Negotiate About Window Size | 窗口大小*/
#define TELNET_NOP 0xf1 /* Unassigned in IANA, putty use this to keepalive */
#define LEN_IAC_CMD 2 /* Only 2 char: |IAC|cmd| */
......@@ -100,9 +137,9 @@
#define TELNET_ACCEPT_INTERVAL 200
/* client settings | 客户端设置*/
#define TELNET_CLIENT_POLL_TIMEOUT 2000
#define TELNET_CLIENT_READ_BUF_SIZE 256
#define TELNET_CLIENT_READ_FILTER_BUF_SIZE (8 * 1024)
#define TELNET_CLIENT_POLL_TIMEOUT 2000 //超时时间设置
#define TELNET_CLIENT_READ_BUF_SIZE 256 //读buf大小
#define TELNET_CLIENT_READ_FILTER_BUF_SIZE (8 * 1024) ///< buf大小
/* limitation: only support 1 telnet client connection */
STATIC volatile INT32 g_telnetClientFd = -1; /* client fd */
......@@ -111,7 +148,7 @@ STATIC volatile INT32 g_telnetClientFd = -1; /* client fd */
STATIC volatile INT32 g_telnetListenFd = -1; /* listen fd of telnetd */
/* each bit for a client connection, although only support 1 connection for now */
STATIC volatile UINT32 g_telnetMask = 0; //掩码
STATIC volatile UINT32 g_telnetMask = 0; //记录有任务打开了远程登录
/* taskID of telnetd */
STATIC atomic_t g_telnetTaskId = 0; ///< 任务ID
/* protect listenFd, clientFd etc. */
......@@ -127,7 +164,7 @@ VOID TelnetUnlock(VOID)
(VOID)pthread_mutex_unlock(&g_telnetMutex);
}
/* filter out iacs from client stream */
/* filter out iacs from client stream | 从客户端流中过滤*/
STATIC UINT8 *ReadFilter(const UINT8 *src, UINT32 srcLen, UINT32 *dstLen)
{
STATIC UINT8 buf[TELNET_CLIENT_READ_FILTER_BUF_SIZE];
......@@ -224,11 +261,11 @@ STATIC ssize_t WriteToFd(INT32 fd, const CHAR *src, size_t srcLen)
return (ssize_t)(srcLen - sizeLeft);
}
/* Try to remove the client device if there is any client connection */
/* Try to remove the client device if there is any client connection | 如果有任务在远程登录,尝试删除它*/
STATIC VOID TelnetClientClose(VOID)
{
/* check if there is any client connection */
if (g_telnetMask == 0) {
if (g_telnetMask == 0) {//没有任务在远程链接,
return;
}
(VOID)TelnetDevDeinit();
......@@ -330,7 +367,7 @@ STATIC INT32 TelnetClientPrepare(INT32 clientFd)
g_telnetClientFd = -1;
return -1;
}
g_telnetMask = 1;
g_telnetMask = 1;//表示有任务在远程登录
/* negotiate with client */
(VOID)WriteToFd(clientFd, (CHAR *)doEcho, sizeof(doEcho));
......
......@@ -359,13 +359,13 @@ unsigned int SysGetPID(void)
{
return LOS_GetCurrProcessID();
}
/// 为指定进程设置进程组ID
int SysSetProcessGroupID(unsigned int pid, unsigned int gid)
{
int ret;
if (pid == 0) {
pid = LOS_GetCurrProcessID();
if (pid == 0) {//无指定进程ID时 @note_thinking 此处会不会有风险, 直接返回会不会好些 ?
pid = LOS_GetCurrProcessID();//获取当前进程ID,给当前进程设置组ID
}
if (gid == 0) {
......@@ -381,7 +381,7 @@ int SysSetProcessGroupID(unsigned int pid, unsigned int gid)
return OsSetProcessGroupID(pid, gid);
}
/// 获取指定进程的组ID,为0时返回当前进程ID
int SysGetProcessGroupID(unsigned int pid)
{
if (pid == 0) {
......@@ -390,12 +390,12 @@ int SysGetProcessGroupID(unsigned int pid)
return LOS_GetProcessGroupID(pid);
}
/// 获取当前进程组ID
int SysGetCurrProcessGroupID(void)
{
return LOS_GetCurrProcessGroupID();
}
/// 获取用户ID
int SysGetUserID(void)
{
return LOS_GetUserID();
......
git add -A
git commit -m ' 开始注解Telnet(远程登录)模块
git commit -m ' 注解LiteIPC(轻量级进程间通信)模块
百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码
鸿蒙研究站 | http://weharmonyos.com (国内)
| https://weharmony.github.io (国外)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册