鸿蒙轻内核A核源码分析系列七 进程管理 (3)

本文记录下进程相关的初始化函数,如OsSystemProcessCreate、OsProcessInit、OsProcessCreateInit、OsUserInitProcess、OsDeInitPCB、OsUserInitProcessStart等。

1、LiteOS-A内核进程创建初始化通用函数

先看看一些内部函数,不管是初始化用户态进程还是内核态进程,都会使用这些函数,包含进程控制块初始化函数OsInitPCB、进程控制块初始化恢复函数OsDeInitPCB

1.1 进程控制块初始化函数OsInitPCB

进程控制块初始化函数OsInitPCB需要3个参数,第一个参数processCB是进程块指针,第二个参数为进程模式mode,分为内核态进程OS_KERNEL_MODE和用户态进程OS_USER_MODE。第三个参数用于设置进程名称。返回值为初始化成功LOS_OK还是失败LOS_ENOMEM。看下代码,⑴处设置进程控制块的信息,用户态进程还是内核态进程,进程状态设置为初始化状态,线程组编号设置为无效值,设置为默认掩码,定时器编号设置为无效值。⑵处初始化进程的双向链表。如果系统配置支持虚拟内存,则执行⑶判断初始化的进程是否为用户态进程,如果是用户态进程,则创建虚拟地址空间,如果创建失败,则把进程状态设置为未使用状态,然后返回错误码。⑷处表示如果是内核态进程,则指定进程的内核进程虚拟地址空间。有关虚拟地址空间的信息,请参考之前的系列文章。

如果执行CPUP特性,则执行⑸处代码,则为CPUP结构体申请内存空间。⑹处,如果开启了LOSCFG_SECURITY_VID,则V初始化ID映射链表。⑺处,如果开启了安全能力LOSCFG_SECURITY_CAPABILITY,则进行相应的初始化。⑻处为进程设置一个名称。

    STATIC UINT32 OsInitPCB(LosProcessCB *processCB, UINT32 mode, const CHAR *name)
    {
⑴      processCB->processMode = mode;
        processCB->processStatus = OS_PROCESS_STATUS_INIT;
        processCB->parentProcessID = OS_INVALID_VALUE;
        processCB->threadGroupID = OS_INVALID_VALUE;
        processCB->umask = OS_PROCESS_DEFAULT_UMASK;
        processCB->timerID = (timer_t)(UINTPTR)MAX_INVALID_TIMER_VID;

⑵      LOS_ListInit(&processCB->threadSiblingList);
        LOS_ListInit(&processCB->childrenList);
        LOS_ListInit(&processCB->exitChildList);
        LOS_ListInit(&(processCB->waitList));

    #ifdef LOSCFG_KERNEL_VM
⑶      if (OsProcessIsUserMode(processCB)) {
            processCB->vmSpace = OsCreateUserVmSpace();
            if (processCB->vmSpace == NULL) {
                processCB->processStatus = OS_PROCESS_FLAG_UNUSED;
                return LOS_ENOMEM;
            }
        } else {
⑷          processCB->vmSpace = LOS_GetKVmSpace();
        }
    #endif

    #ifdef LOSCFG_KERNEL_CPUP
⑸      processCB->processCpup = (OsCpupBase *)LOS_MemAlloc(m_aucSysMem1, sizeof(OsCpupBase));
        if (processCB->processCpup == NULL) {
            return LOS_ENOMEM;
        }
        (VOID)memset_s(processCB->processCpup, sizeof(OsCpupBase), 0, sizeof(OsCpupBase));
    #endif

    #ifdef LOSCFG_SECURITY_VID
⑹      status_t status = VidMapListInit(processCB);
        if (status != LOS_OK) {
            return LOS_ENOMEM;
        }
    #endif

⑺  #ifdef LOSCFG_SECURITY_CAPABILITY
        OsInitCapability(processCB);
    #endif

⑻      if (OsSetProcessName(processCB, name) != LOS_OK) {
            return LOS_ENOMEM;
        }

        return LOS_OK;
    }

1.2 进程控制块初始化恢复函数OsDeInitPCB

在创建进程时,会执行该函数,恢复进程控制块信息到初始化之前的状态。⑴处释放进程的资源,包含地址空间、文件、安全能力、定时器等占用的内存。如果存在父进程,则执行⑵从父进程的兄弟列表上删除。如果进程属于进程组,则从进程组中退出。然后执行⑷设置进程状态为退出态,把进程放入待回收链表中。

    STATIC VOID OsDeInitPCB(LosProcessCB *processCB)
    {
        UINT32 intSave;
        ProcessGroup *group = NULL;

        if (processCB == NULL) {
            return;
        }

⑴      OsProcessResourcesToFree(processCB);

        SCHEDULER_LOCK(intSave);
        if (processCB->parentProcessID != OS_INVALID_VALUE) {
⑵          LOS_ListDelete(&processCB->siblingList);
            processCB->parentProcessID = OS_INVALID_VALUE;
        }

⑶      if (processCB->group != NULL) {
            OsExitProcessGroup(processCB, &group);
        }

⑷      processCB->processStatus &= ~OS_PROCESS_STATUS_INIT;
        processCB->processStatus |= OS_PROCESS_FLAG_EXIT;
        LOS_ListHeadInsert(&g_processRecycleList, &processCB->pendList);
        SCHEDULER_UNLOCK(intSave);

        (VOID)LOS_MemFree(m_aucSysMem1, group);
        OsWriteResourceEvent(OS_RESOURCE_EVENT_FREE);
        return;
    }

2、 LiteOS-A内核系统进程创建函数OsSystemProcessCreate

系统进程创建函数OsSystemProcessCreate在文件kernel\common\los_config.c中被调用,在系统启动阶段创建系统进程。该函数又调用OsProcessInit,我们首先看下函数OsProcessInit。

2.1 进程初始化函数OsProcessInit

进程初始化函数OsProcessInit为进程控制块申请内存,初始化进程相关的进程链表。我们看下代码,⑴处获取配置的进程最大数值,然后计算需要的内存大小。⑵处申请内存,初始化申请的内存块。⑶处初始化空闲进程双向链表和待回收进程双向链表。
⑷处初始化每一个进程,社区进程编号、进程状态,然后把每一个进程放到空闲进程链表里。⑸处设置Idle进程编号为0,用户根进程编号为1,系统根进程编号为2,然后执行LOS_ListDelete把这3个进程从阻塞链表上删除。

    STATIC UINT32 OsProcessInit(VOID)
    {
        UINT32 index;
        UINT32 size;

⑴      g_processMaxNum = LOSCFG_BASE_CORE_PROCESS_LIMIT;
        size = g_processMaxNum * sizeof(LosProcessCB);

⑵      g_processCBArray = (LosProcessCB *)LOS_MemAlloc(m_aucSysMem1, size);
        if (g_processCBArray == NULL) {
            return LOS_NOK;
        }
        (VOID)memset_s(g_processCBArray, size, 0, size);

⑶      LOS_ListInit(&g_freeProcess);
        LOS_ListInit(&g_processRecycleList);

⑷      for (index = 0; index < g_processMaxNum; index++) {
            g_processCBArray[index].processID = index;
            g_processCBArray[index].processStatus = OS_PROCESS_FLAG_UNUSED;
            LOS_ListTailInsert(&g_freeProcess, &g_processCBArray[index].pendList);
        }

⑸      g_kernelIdleProcess = 0; /* 0: The idle process ID of the kernel-mode process is fixed at 0 */
        LOS_ListDelete(&OS_PCB_FROM_PID(g_kernelIdleProcess)->pendList);

        g_userInitProcess = 1; /* 1: The root process ID of the user-mode process is fixed at 1 */
        LOS_ListDelete(&OS_PCB_FROM_PID(g_userInitProcess)->pendList);

        g_kernelInitProcess = 2; /* 2: The root process ID of the kernel-mode process is fixed at 2 */
        LOS_ListDelete(&OS_PCB_FROM_PID(g_kernelInitProcess)->pendList);

        return LOS_OK;
    }

2.2 进程创建初始化函数OsProcessCreateInit

该函数用于创建进程时的一些初始化操作,主要是文件系统、安全能力、进程组等等。需要3个参数,分别是进程控制块指针,标记用户态还是内核态进程的flags,进程名称name。首先执行⑴调用OsInitPCB()对进程控制块进行初始化,然后,如果配置支持了虚拟文件系统VFS,则执行⑵为进程分别文件。⑶处根据进程号创建进程组。如果支持安全能力,则执行⑷创建用户。如果初始化失败,会执行⑸恢复进程控制块到初始化之前的状态。

    STATIC UINT32 OsProcessCreateInit(LosProcessCB *processCB, UINT32 flags, const CHAR *name)
    {
        ProcessGroup *group = NULL;
⑴      UINT32 ret = OsInitPCB(processCB, flags, name);
        if (ret != LOS_OK) {
            goto EXIT;
        }

    #ifdef LOSCFG_FS_VFS
⑵      processCB->files = alloc_files();
        if (processCB->files == NULL) {
            ret = LOS_ENOMEM;
            goto EXIT;
        }
    #endif

⑶      group = OsCreateProcessGroup(processCB->processID);
        if (group == NULL) {
            ret = LOS_ENOMEM;
            goto EXIT;
        }

    #ifdef LOSCFG_SECURITY_CAPABILITY
⑷      processCB->user = OsCreateUser(0, 0, 1);
        if (processCB->user == NULL) {
            ret = LOS_ENOMEM;
            goto EXIT;
        }
    #endif

        return LOS_OK;

    EXIT:
⑸      OsDeInitPCB(processCB);
        return ret;
    }

2.3 系统进程创建函数OsSystemProcessCreate

接下来,我们看看系统进程创建函数OsSystemProcessCreate的源代码。⑴处开始先后调用OsProcessInit、OsProcessCreateInit初始化内核态根进程,⑵处进程的状态不再是初始化状态。⑶处从内核进程获取全局进程组指针g_processGroup,然后初始化进程组的双向链表。这样看来,所有的进程组都会挂载到内核进程的进程组节点上。⑷处初始化内核空闲进程,内核空闲进程的父进程也是内核态根进程,插入到进程组链表,设置空闲进程的状态不再是初始化状态。执行⑸创建空闲任务,然后设置空闲进程的线程组编号为空闲线程编号。

    LITE_OS_SEC_TEXT_INIT UINT32 OsSystemProcessCreate(VOID)
    {
⑴      UINT32 ret = OsProcessInit();
        if (ret != LOS_OK) {
            return ret;
        }

        LosProcessCB *kerInitProcess = OS_PCB_FROM_PID(g_kernelInitProcess);
        ret = OsProcessCreateInit(kerInitProcess, OS_KERNEL_MODE, "KProcess");
        if (ret != LOS_OK) {
            return ret;
        }

⑵      kerInitProcess->processStatus &= ~OS_PROCESS_STATUS_INIT;
⑶      g_processGroup = kerInitProcess->group;
        LOS_ListInit(&g_processGroup->groupList);

⑷      LosProcessCB *idleProcess = OS_PCB_FROM_PID(g_kernelIdleProcess);
        ret = OsInitPCB(idleProcess, OS_KERNEL_MODE, "KIdle");
        if (ret != LOS_OK) {
            return ret;
        }
        idleProcess->parentProcessID = kerInitProcess->processID;
        LOS_ListTailInsert(&kerInitProcess->childrenList, &idleProcess->siblingList);
        idleProcess->group = kerInitProcess->group;
        LOS_ListTailInsert(&kerInitProcess->group->processList, &idleProcess->subordinateGroupList);
    #ifdef LOSCFG_SECURITY_CAPABILITY
        idleProcess->user = kerInitProcess->user;
    #endif
    #ifdef LOSCFG_FS_VFS
        idleProcess->files = kerInitProcess->files;
    #endif
        idleProcess->processStatus &= ~OS_PROCESS_STATUS_INIT;

⑸      ret = OsIdleTaskCreate();
        if (ret != LOS_OK) {
            return ret;
        }
        idleProcess->threadGroupID = OsGetIdleTaskId();

        return LOS_OK;
    }

3. LiteOS-A内核用户进程创建函数OsUserInitProcess

系统启动阶段,OsUserInitProcess启动init进程。该函数在device开发板目录下系统初始化文件中调用,如system_init.c等等。该函数需要开启LOSCFG_KERNEL_DYNLOAD宏,否则函数体内容为空。在阅读函数OsUserInitProcess的源码前,先看看该函数调用的其他函数,如OsLoadUserInit、OsUserInitStackAlloc、OsUserInitProcessStart等等。

3.1 加载用户初始化数据函数OsLoadUserInit

该函数用于加载用户数据。⑴处从链接脚本获取text、bss的开启和结束地址,然后计算bss段、初始化段的大小。⑵处进行一些必要的校验,是否针对内存页对齐,内存段长度是否合理等。然后执行⑶,申请物理内存页,然后把用户初始化数据复制到申请的内存页。⑷处进行虚实映射。如果bss段长度不为0,执行⑸把bss段的内存区域清零。

STATIC UINT32 OsLoadUserInit(LosProcessCB *processCB)
{
    /*              userInitTextStart               -----
     * | user text |
     *
     * | user data |                                initSize
     *              userInitBssStart  ---
     * | user bss  |                  initBssSize
     *              userInitEnd       ---           -----
     */
    errno_t errRet;
    INT32 ret;
⑴  CHAR *userInitTextStart = (CHAR *)&__user_init_entry;
    CHAR *userInitBssStart = (CHAR *)&__user_init_bss;
    CHAR *userInitEnd = (CHAR *)&__user_init_end;
    UINT32 initBssSize = userInitEnd - userInitBssStart;
    UINT32 initSize = userInitEnd - userInitTextStart;
    VOID *userBss = NULL;
    VOID *userText = NULL;

⑵  if ((LOS_Align((UINTPTR)userInitTextStart, PAGE_SIZE) != (UINTPTR)userInitTextStart) ||
        (LOS_Align((UINTPTR)userInitEnd, PAGE_SIZE) != (UINTPTR)userInitEnd)) {
        return LOS_EINVAL;
    }

    if ((initSize == 0) || (initSize <= initBssSize)) {
        return LOS_EINVAL;
    }

⑶  userText = LOS_PhysPagesAllocContiguous(initSize >> PAGE_SHIFT);
    if (userText == NULL) {
        return LOS_NOK;
    }

    errRet = memcpy_s(userText, initSize, (VOID *)&__user_init_load_addr, initSize - initBssSize);
    if (errRet != EOK) {
        PRINT_ERR("Load user init text, data and bss failed! err : %d\n", errRet);
        goto ERROR;
    }
⑷  ret = LOS_VaddrToPaddrMmap(processCB->vmSpace, (VADDR_T)(UINTPTR)userInitTextStart, LOS_PaddrQuery(userText),
                               initSize, VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE |
                               VM_MAP_REGION_FLAG_FIXED | VM_MAP_REGION_FLAG_PERM_EXECUTE |
                               VM_MAP_REGION_FLAG_PERM_USER);
    if (ret < 0) {
        PRINT_ERR("Mmap user init text, data and bss failed! err : %d\n", ret);
        goto ERROR;
    }

    /* The User init boot segment may not actually exist */
⑸  if (initBssSize != 0) {
        userBss = (VOID *)((UINTPTR)userText + userInitBssStart - userInitTextStart);
        errRet = memset_s(userBss, initBssSize, 0, initBssSize);
        if (errRet != EOK) {
            PRINT_ERR("memset user init bss failed! err : %d\n", errRet);
            goto ERROR;
        }
    }

    return LOS_OK;

ERROR:
    (VOID)LOS_PhysPagesFreeContiguous(userText, initSize >> PAGE_SHIFT);
    return LOS_NOK;
}

3.2 用户初始化栈函数OsUserInitStackAlloc

该函数需要2个参数,第一个参数为进程控制块,第二个参数为输出参数,用于获取用户任务栈的大小。⑴处用户任务栈大小对页进行对齐,然后申请内存区域,然后执行⑵设置内存区域类型,并社区内存区域标签为栈。然后设置输出参数为任务栈大小,并返回用户栈空间的开始地址。

STATIC VOID *OsUserInitStackAlloc(LosProcessCB *processCB, UINT32 *size)
{
    LosVmMapRegion *region = NULL;
⑴  UINT32 stackSize = ALIGN(OS_USER_TASK_STACK_SIZE, PAGE_SIZE);

    region = LOS_RegionAlloc(processCB->vmSpace, 0, stackSize,
                             VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_READ |
                             VM_MAP_REGION_FLAG_PERM_WRITE, 0);
    if (region == NULL) {
        return NULL;
    }

⑵  LOS_SetRegionTypeAnon(region);
    region->regionFlags |= VM_MAP_REGION_FLAG_STACK;

    *size = stackSize;

    return (VOID *)(UINTPTR)region->range.base;
}

3.3 用户进程初始化开启函数OsUserInitProcessStart

用户进程初始化开启函数OsUserInitProcessStart用于创建线程,设置调度策略等。⑴处为用户态进程创建个线程,然后为进程设置优先级。⑵处设置进程状态为非初始化状态,然后执行⑶为任务设置调度策略和优先级。

STATIC UINT32 OsUserInitProcessStart(LosProcessCB *processCB, TSK_INIT_PARAM_S *param)
{
    UINT32 intSave;
    INT32 ret;

⑴  UINT32 taskID = OsCreateUserTask(processCB->processID, param);
    if (taskID == OS_INVALID_VALUE) {
        return LOS_NOK;
    }

    ret = LOS_SetProcessPriority(processCB->processID, OS_PROCESS_USERINIT_PRIORITY);
    if (ret != LOS_OK) {
        PRINT_ERR("User init process set priority failed! ERROR:%d \n", ret);
        goto EXIT;
    }

    SCHEDULER_LOCK(intSave);
⑵  processCB->processStatus &= ~OS_PROCESS_STATUS_INIT;
    SCHEDULER_UNLOCK(intSave);

⑶  ret = LOS_SetTaskScheduler(taskID, LOS_SCHED_RR, OS_TASK_PRIORITY_LOWEST);
    if (ret != LOS_OK) {
        PRINT_ERR("User init process set scheduler failed! ERROR:%d \n", ret);
        goto EXIT;
    }

    return LOS_OK;

EXIT:
    (VOID)LOS_TaskDelete(taskID);
    return ret;
}

3.4 用户态进程初始化函数OsUserInitProcess

用户态进程初始化函数OsUserInitProcess完成用户态进程的初始化。⑴处获取用户态根进程,然后调用函数创建用户态根进程,并调用函数OsLoadUserInit加载用户初始化数据。⑵处初始化用户栈,然后设置线程的初始化参数,⑶处完成用户态进程的创建。

LITE_OS_SEC_TEXT_INIT UINT32 OsUserInitProcess(VOID)
{
    UINT32 ret;
    UINT32 size;
    TSK_INIT_PARAM_S param = { 0 };
    VOID *stack = NULL;

⑴  LosProcessCB *processCB = OS_PCB_FROM_PID(g_userInitProcess);
    ret = OsProcessCreateInit(processCB, OS_USER_MODE, "Init");
    if (ret != LOS_OK) {
        return ret;
    }

    ret = OsLoadUserInit(processCB);
    if (ret != LOS_OK) {
        goto ERROR;
    }

⑵  stack = OsUserInitStackAlloc(processCB, &size);
    if (stack == NULL) {
        PRINT_ERR("Alloc user init process user stack failed!\n");
        goto ERROR;
    }

    param.pfnTaskEntry = (TSK_ENTRY_FUNC)(CHAR *)&__user_init_entry;
    param.userParam.userSP = (UINTPTR)stack + size;
    param.userParam.userMapBase = (UINTPTR)stack;
    param.userParam.userMapSize = size;
    param.uwResved = OS_TASK_FLAG_PTHREAD_JOIN;
⑶  ret = OsUserInitProcessStart(processCB, &param);
    if (ret != LOS_OK) {
        (VOID)OsUnMMap(processCB->vmSpace, param.userParam.userMapBase, param.userParam.userMapSize);
        goto ERROR;
    }

    return LOS_OK;

ERROR:
    OsDeInitPCB(processCB);
    return ret;
}

小结

本文介绍了进程管理的内核进程、用户态进程的初始化相关函数。

如果大家想更加深入的学习 OpenHarmony 开发的内容,不妨可以参考以下相关学习文档进行学习,助你快速提升自己:

OpenHarmony 开发环境搭建:https://qr18.cn/CgxrRy

《OpenHarmony源码解析》:https://qr18.cn/CgxrRy

  • 搭建开发环境
  • Windows 开发环境的搭建
  • Ubuntu 开发环境搭建
  • Linux 与 Windows 之间的文件共享
  • ……

系统架构分析:https://qr18.cn/CgxrRy

  • 构建子系统
  • 启动流程
  • 子系统
  • 分布式任务调度子系统
  • 分布式通信子系统
  • 驱动子系统
  • ……

OpenHarmony 设备开发学习手册:https://qr18.cn/CgxrRy

在这里插入图片描述

OpenHarmony面试题(内含参考答案):https://qr18.cn/CgxrRy

写在最后

  • 如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
  • 想要获取更多完整鸿蒙最新学习资源,请移步前往小编:https://qr21.cn/FV7h05

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/706013.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

收银系统小程序商城商品详情页再升级!

本期导读 1.新增&#xff1a;商品详情页新增商品参数模块&#xff1b; 2.新增&#xff1a;商品详情页新增保障服务模块&#xff1b; 3.新增&#xff1a;线上商城商品新增划线价&#xff1b; 4.新增&#xff1a;线上商城分销商品新增“赚”字标签及预收收益&#xff1b; 5.…

Linux-笔记 全志平台OTG虚拟 串口、网口、U盘笔记

前言&#xff1a; 此文章方法适用于全志通用平台&#xff0c;并且三种虚拟功能同一时间只能使用一个&#xff0c;原因是此3种功能都是内核USB Gadget precomposed configurations的其中一个选项&#xff0c;只能单选&#xff0c;不能多选&#xff0c;而且不能通过修改配置文件去…

我的考研经历

当我写下这篇文章时&#xff0c;我已经从考研 的失败中走出来了&#xff0c;考研的整个过程都写在博客日志里面了&#xff0c;在整理并阅读考研的日志时&#xff0c;想写下一篇总结&#xff0c;也算是为了更好的吸取教训。 前期日志模板&#xff1a;时间安排的还算紧凑&#x…

安鸾学院靶场——安全基础

文章目录 1、Burp抓包2、指纹识别3、压缩包解密4、Nginx整数溢出漏洞5、PHP代码基础6、linux基础命令7、Mysql数据库基础8、目录扫描9、端口扫描10、docker容器基础11、文件类型 1、Burp抓包 抓取http://47.100.220.113:8007/的返回包&#xff0c;可以拿到包含flag的txt文件。…

DDei在线设计器-配置主题风格

DDeiCore-主题 DDei-Core插件提供了默认主题和黑色主题。 如需了解详细的API教程以及参数说明&#xff0c;请参考DDei文档 默认主题 黑色主题 使用指南 引入 import { DDeiCoreThemeBlack } from "ddei-editor";使用并修改设置 extensions: [......//通过配置&am…

【FreeRTOS】内存管理

目录 1 为什么要自己实现内存管理2 FreeRTOS的5中内存管理方法2.1 Heap_12.2 Heap_22.3 Heap_32.4 Heap_4 2.5 Heap_53 Heap相关的函数3.1 pvPortMalloc/vPortFree3.2 xPortGetFreeHeapSize 3.3 xPortGetMinimumEverFreeHeapSize3.4 malloc失败的钩子函数 参考《FreeRTOS入门与…

Python私教张大鹏 Vue3整合AntDesignVue之DatePicker 日期选择框

案例&#xff1a;选择日期 <script setup> import {ref} from "vue";const date ref(null) </script> <template><div class"p-8 bg-indigo-50 text-center"><a-date-picker v-model:value"date"/><a-divide…

原子阿波罗STM32F429程序的控制器改为STM32F407驱动LCD屏

原子大神的阿波罗开发板使用STM32F429IGT6控制器&#xff0c;编程风格也与探索者F407系列有了很大的不同&#xff0c;使用BSP功能模块编程了&#xff0c;也有点类似于安富莱的编程风格了。这种模块式程序风格的优点是更加方便移植&#xff0c;更方便泡系统。 但无奈手里只有F40…

模拟笔试 - 卡码网周赛第二十一期(23年美团笔试真题)

第一题&#xff1a;小美的排列询问 解题思路: 简单题&#xff0c;一次遍历数组&#xff0c;判断 是否有和x、y相等并且相连 即可。 可优化逻辑&#xff1a;因为x和y是后输入的&#xff0c;必须存储整个数组&#xff0c;但是上面说了 **排列是指一个长度为n的数组&#xff0…

搭建一个好玩的 RSS 订阅网站记录

全文相关链接 Github仓库创建链接Railway官网Supabase官网f-droid上的co.appreactor.news应用下载链接Railway账户使用量估算链接 全文相关代码 原文地址: https://blog.taoshuge.eu.org/p/270/ Dockerfile FROM docker.io/miniflux/miniflux:2.1.3环境变量 DATABASE_URL…

UniApp或微信小程序中scroll-view组件使用show-scrollbar在真机Android或IOS中隐藏不了滚动条的解决办法

show-scrollbar 属性 不论是使用 变量 还是直接使用 布尔值或者直接使用 css 都是在 ios、Android 上是都没有效果。。 真机中还是出现滚动条 解决办法 添加下面CSS ::-webkit-scrollbar {display: none;width: 0 !important;height: 0 !important;-webkit-appearance: no…

Charles代理https接口到本地

一、操作手册 1、安装工具 1.1、安装代理软件Charles 软件下载地址&#xff1a;Download a Free Trial of Charles • Charles Web Debugging Proxy 1.2、安装https代理插件&#xff1a;&#xff08;有问题自行百度解决&#xff09; 2、配置策略 以下以https接口为例&…

mysql索引B+树可视化演示地址

https://www.cs.usfca.edu/~galles/visualization/BPlusTree.html

RISE - Ultimate Project Manager CRM 3.6.1 中文版安装指南

RISE 是一个多用途项目管理系统&#xff0c;有助于任何类型的企业管理他们的工作。它可以节省您管理客户、项目、销售和团队成员的日常时间。可提高客户满意度和工作绩效。 安装系统 登录宝塔&#xff0c;添加站点 输入域名和数据库信息&#xff0c;PHP版本至少是8.1 添加完成…

下载kibana-7.10.2教程

1、官网下载地址&#xff1a; Download Kibana Free | Get Started Now | Elastic 2、进入 Kibana下载界面&#xff0c;点击 View past releases 查看过去的版本 3、选择版本 Elasticsearch 7.10.2&#xff0c;点击 Download 4、点击 LINUX 64-BIT&#xff0c;进行下载 5、下…

docker-compose Install it-tools

IT-Tools前言 IT-Tools是一款开源的个人工具箱,专为IT从业人员打造,支持Docker私有化部署,包含众多实用的IT工具。其功能丰富多样,涵盖二维码生成、数据格式转换、MAC地址生成等,可满足用户多样化的需求。 前提要求 安装 docker docker-compose 参考创建一键部署it-tool…

码农学点儿经济学-博傻理论

博傻理论 一位石油大佬去天堂开会&#xff0c;他兴冲冲地跑进会议室&#xff0c;却发现座无虚席&#xff0c;早已经没了他的座位。于是他灵机一动&#xff0c;大喊一声&#xff1a;大家注意啦&#xff01;听说&#xff0c;有人在地狱发现了石油&#xff01;此言一出&#xff0c…

电脑桌面上用来记事的便签软件

便签软件已成为我们日常生活中不可或缺的记录工具。想象一下&#xff0c;在繁忙的工作中&#xff0c;你突然需要记下一个重要事项或临时想法&#xff0c;这时&#xff0c;一个便捷、高效的便签软件就显得尤为重要。它能帮助我们迅速捕捉信息&#xff0c;轻松管理琐碎事务&#…

22 CRT工具安装流程

22 CRT工具安装流程 SecureCRT 9.5 说明书 SecureCRT 9.5是一款由VanDyke Software开发的终端仿真程序。它为Windows、Mac和Linux操作系统提供了强大的SSH&#xff08;Secure Shell&#xff09;客户端功能。SecureCRT 9.5提供了对Telnet、RLogin、Serial和X.509等协议的支持&…