nuttx-app的编译和执行原理

2023-05-16

首先阅读apps/readme.md

## Built-In Applications 
 NuttX also supports applications that can be started using a name string. In
 this case, application entry points with their requirements are gathered
 together in two files:
 
 - `builtin/builtin_proto.h` – Entry points, prototype function
 - `builtin/builtin_list.h` – Application specific information and requirements
 
 The build occurs in several phases as different build targets are executed: (1)
 context, (2) depend, and (3) default (all). Application information is collected
 during the make context build phase.
  
 To execute an application function:
 
 `exec_builtin()` is defined in the `apps/include/builtin/builtin.h`.

## NuttShell (NSH) Built-In Commands
 
 One use of builtin applications is to provide a way of invoking your custom
 application through the NuttShell (NSH) command line. NSH will support a
 seamless method invoking the applications, when the following option is enabled
 in the NuttX configuration file:
 
 ```conf
 CONFIG_NSH_BUILTIN_APPS=y
 ```
 
 Applications registered in the `apps/builtin/builtin_list.h` file will then be
 accessible from the NSH command line. If you type `help` at the NSH prompt, you
 will see a list of the registered commands.

根据readme文件中的描述,查找关键文件builtin_list.h和builtin_proto.h

apps/builtin/Makefile文件中,找到builtin_list.h和builtin_proto.h的生成规则。

builtin_list.h: registry$(DELIM).updated
ifeq ($(BDATLIST),)
    $(call DELFILE, builtin_list.h)
    $(Q) touch builtin_list.h
else
    $(call CATFILE, builtin_list.h, $(BDATLIST))
endif

builtin_proto.h: registry$(DELIM).updated
ifeq ($(PDATLIST),)
    $(call DELFILE, builtin_proto.h)
    $(Q) touch builtin_proto.h
else
    $(call CATFILE, builtin_proto.h, $(PDATLIST))
endif

从Makfile上和实际文件内容能够看出,

builtin_list.h整合了registry目录下的bdat文件内容

builtin_proto.h整合了registry目录下的pdat文件内容

那么,这些bdat和pdat文件又是怎么来的?在apps/Make.defs中定义了REGISTER函数

define REGISTER
    $(Q) echo Register: $1
    $(Q) echo { \"$1\", $2, $3, $4 }, > "$(BUILTIN_REGISTRY)$(DELIM)$1.bdat"
    $(Q) if [ ! -z $4 ]; then \
            echo "int $4(int argc, char *argv[]);" > "$(BUILTIN_REGISTRY)$(DELIM)$1.pdat"; \
         fi; 
    $(Q) touch "$(BUILTIN_REGISTRY)$(DELIM).updated"
endef 

apps/Application.mk中进行了调用 

$(call REGISTER,$(firstword $(APPLIST)),$(firstword $(PRIORITY)),$(firstword $(STACKSIZE)),$(if $(BUILD_MODULE),,$(firstword $(APPLIST))_main))

APPLIST:继承自PROGNAME,也就是apps/examples/demo/Makefile中的

来自于apps/examples/demo/Kconfig中的配置项,REGISTER函数的其他几项形参,也是如此。

 config EXAMPLES_DEMO_PROGNAME                                                                                                                                                                          
     string "Program name"
     default "demo"
     ---help---
         This is the name of the program that will be used when the NSH ELF
         program is installed.

至此,builtin_list.h和builtin_proto.h的来历已经弄清楚了。apps/builtin/builtin_list.c中定义了一个关键的结构体数组g_builtins,结构体的定义在nuttx/include/nuttx/lib/builtin.h中。

struct builtin_s                              
{
    const char *name;         /* Invocation name and as seen under /sbin/ */ sbin下显示的名字
    int         priority;             /* Use: SCHED_PRIORITY_DEFAULT */,task优先级
    int         stacksize;         /* Desired stack size */ task栈大小
    main_t      main;            /* Entry point: main(int argc, char *argv[]) */ 线程入口函数指针
};

#include "builtin_proto.h"

const struct builtin_s g_builtins[] =
{
# include "builtin_list.h"
  { NULL, 0, 0, 0 }
};

const int g_builtin_count = sizeof(g_builtins) / sizeof(g_builtins[0]);

展开后:

int demo_main(int argc, char *argv[]);
int nsh_main(int argc, char *argv[]);
int sh_main(int argc, char *argv[]);
int gpio_main(int argc, char *argv[]);
int hello_main(int argc, char *argv[]);

const struct builtin_s g_builtins[] =
{
  { "demo", 100, 2048, demo_main },
  { "sh", 100, 2048, sh_main },
  { "hello", 100, 2048, hello_main },
  { "nsh", 100, 2048, nsh_main },
  { "gpio", 100, 2048, gpio_main },
  { NULL, 0, 0, 0 }
};

编译完成后,nuttx在nsh中进行人机交互,下面是app启动的流程。

apps/nshlib/nsh_parse.c中的nsh_parse-->

apps/nshlib/nsh_parse.c中的nsh_parse_cmdparm和nsh_parse_command--->

apps/nshlib/nsh_parse.c中的nsh_execute--->

apps/nshlib/nsh_builtin.c中nsh_builtin函数---->apps/builtin/exec_builtin.c中的exec_builtin,

int exec_builtin(FAR const char *appname, FAR char * const *argv,
                 FAR const char *redirfile, int oflags)
{
  FAR const struct builtin_s *builtin;
  posix_spawnattr_t attr;
  posix_spawn_file_actions_t file_actions;
  struct sched_param param;
  pid_t pid;
  int index;
  int ret;

  /* Verify that an application with this name exists */

  index = builtin_isavail(appname);                                                                                                                                                                        
  if (index < 0)
    {
      ret = ENOENT;
      goto errout_with_errno;
    }

  /* Get information about the builtin */

  builtin = builtin_for_index(index);
  if (builtin == NULL)
    {
      ret = ENOENT;
      goto errout_with_errno;
    }

  /* Initialize attributes for task_spawn(). */

  ret = posix_spawnattr_init(&attr);
  if (ret != 0)
    {
      goto errout_with_errno;
    }   

  ret = posix_spawn_file_actions_init(&file_actions);
  if (ret != 0)
    {                                                                                                                                                                                                      
      goto errout_with_attrs;
    }

  /* Set the correct task size and priority */

  param.sched_priority = builtin->priority;
  ret = posix_spawnattr_setschedparam(&attr, &param);
  if (ret != 0)
    {
      goto errout_with_actions;
    }

  ret = task_spawnattr_setstacksize(&attr, builtin->stacksize);
  if (ret != 0)
    {
      goto errout_with_actions;
    }

  /* If robin robin scheduling is enabled, then set the scheduling policy
   * of the new task to SCHED_RR before it has a chance to run.
   */

#if CONFIG_RR_INTERVAL > 0
  ret = posix_spawnattr_setschedpolicy(&attr, SCHED_RR);
  if (ret != 0)
    {
      goto errout_with_actions;
    }

  ret = posix_spawnattr_setflags(&attr,
                                 POSIX_SPAWN_SETSCHEDPARAM |
                                 POSIX_SPAWN_SETSCHEDULER);
  if (ret != 0)
    {
      goto errout_with_actions;
    }

#else
  ret = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSCHEDPARAM);
  if (ret != 0)
    {
      goto errout_with_actions;
    }

#endif

  /* Is output being redirected? */
  if (redirfile)
    {
      /* Set up to close open redirfile and set to stdout (1) */

      ret = posix_spawn_file_actions_addopen(&file_actions, 1,
                                             redirfile, oflags, 0644);
      if (ret != 0)
        {
          serr("ERROR: posix_spawn_file_actions_addopen failed: %d\n", ret);
          goto errout_with_actions;
        }
    }

#ifdef CONFIG_LIBC_EXECFUNCS
  /* Load and execute the application. */

  ret = posix_spawn(&pid, builtin->name, &file_actions, &attr, argv, NULL);
  if (ret != 0 && builtin->main != NULL)
#endif
    {
      /* Start the built-in */

      pid = task_spawn(builtin->name, builtin->main, &file_actions,
                       &attr, (argv) ? &argv[1] : (FAR char * const *)NULL,
                       (FAR char * const *)NULL);
      ret = pid < 0 ? -pid : 0;
    }

  if (ret != 0)
    {
      serr("ERROR: task_spawn failed: %d\n", ret);
      goto errout_with_actions;
    }

  /* Free attributes and file actions.  Ignoring return values in the case
   * of an error.
   */

  /* Return the task ID of the new task if the task was successfully
   * started.  Otherwise, ret will be ERROR (and the errno value will
   * be set appropriately).
   */

  posix_spawn_file_actions_destroy(&file_actions);
  posix_spawnattr_destroy(&attr);
  return pid;

errout_with_actions:
  posix_spawn_file_actions_destroy(&file_actions);

errout_with_attrs:
  posix_spawnattr_destroy(&attr);

errout_with_errno:
  errno = ret;
  return ERROR;
}



最终通过下面的接口实现了任务的创建,虽然每个任务有自己的栈,但是由于内存,在没有MMU的情况下,如果同一个app启动了多个实例,app中使用的全局变量、静态变量等存放在bss段、data段的数据,多个实例将共享该变量,都可以进行修改,所以需要特别注意。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

nuttx-app的编译和执行原理 的相关文章

随机推荐

  • FreeRTOS移植STM32

    第一步 xff1a FreeRTOS官网 https www freertos org https www freertos org 第二步 xff1a OS移植文件 复制 FreeRTOSv202104 00 FreeRTOS Sourc
  • freeOS-----primask faultmask basepri中断屏蔽寄存器

    primask暂时屏蔽中断寄存器 在许多应用中 需要暂时屏蔽所有的中断一执行一些对时序要求严格的任务 这个时候就 可以使用 PRIMASK 寄存器 PRIMASK 用于禁止除 复位 NMI 不可屏蔽中断 和 HardFalut 硬故障寄存器
  • freeOS快速笔记-----任务4种状态

    运行态 当一个任务正在运行时 那么就说这个任务处于运行态 处于运行态的任务就是当前正在 使用处理器的任务 如果使用的是单核处理器的话那么不管在任何时刻永远都只有一个任务处于运行态 就绪态 处于就绪态的任务是那些已经准备就绪 这些任务没有被阻
  • freeOS笔记-----列表与列表项

    xff08 2 xff09 uxNumberOfItems 用来记录列表中列表项的数量 xff08 3 xff09 pxIndex 用来记录当前列表项索引号 用于遍历列表 xff08 4 xff09 列表中最后一个列表项 用来表示列表结束
  • FreeRTOS快速笔记————队列

    队列 xff08 任务之间 全局变量 xff09 在实际的应用中 常常会遇到一个任务或者中断服务需要和另外一个任务进行 沟通交流 这个 沟通交流 的过程其实就是消息传递的过程 在没有操作系统的时候两个应用程序进行 消息传递一般使用全局变量的
  • FreeRTOS快速笔记——信号量

    信号量的阻塞时间 单位是系统的节拍周期configTICK RATE HZ 为100 xff0c 则系统节拍时钟周期为10ms xff0c 设置0就是不等待 xff0c 设置1 无限就是按时钟节拍算时间 xff0c 设置portMAX DE
  • Python获取Excel中超链接并下载至本地

    在这一任务的处理中 xff0c 我是用的是 xlrd模块 xff0c 它是用来读取Excel表格数据的模块 特别注意 xff1a 高版本的xlrd目前去除了对xlsx格式的支持 xff0c 仅支持 xls格式 xlrd biffh XLRD
  • MATLAB:梯度下降法求解一元和多元函数极小值和极大值

    梯度下降法 xff0c 顾名思义即通过梯度下降的方法 对于一个函数而言 xff0c 梯度是一个向量 xff0c 方向是表示函数值增长最快的方向 xff0c 而大小则表示该方向的导数 下面展示了用梯度下降法求解一元函数的MATLAB代码 xf
  • 根据Qfont中的family 得到字体文件的路径和文件名称

    转载 xff1a https www zhihu com question 25834024 根据Qfont中的family 得到字体文件的路径和文件名称 xff1b 源码 xff1a 头文件 include include include
  • 如何修改DirectUIHWND类里控件的数据

    有成功修改SysTlistView32 SysTreeVier32 ListVier32 Static类的方法 但对VISTA系统的DirectUIHWND类 没有好的办法 恳请高人指教
  • Jeston-TX2和小觅智能魔方安装tensorflow和keras

    1 下载TensorFlow离线文件 根据自己的JetPack版本在下面链接中选择对应的tensorflow 链接为tensorflow下载链接 如图所示 2 使用pip安装TensorFlow xff0c 如果是Python2用pip2
  • 2023python自动化抢单茅台

    2023python自动化下单抢茅台 xff08 小白篇 xff09 提前声明 本人实测一周 xff0c 均以失败告终 网络超时 当前人数过多等等原因 人格担保程序没有问题 xff0c 毕竟天底下那有这么好的事 最终结果不是重要的 xff0
  • [React] 核心属性refs—— 需要注意的问题

    官网链接 xff1a Refs and the DOM React 1 避免使用字符串的ref 什么是字符串的ref lt button ref 61 34 test 34 gt lt button gt ref所赋予的值是一个字符串 官方
  • AIDL-JNI-HIDL

    Android项目开发经常会遇到各种概念性的技术 AIDL xff08 Android Interface definition language xff09 Android中的一种IPC xff08 Inter Process Commu
  • Android Verified Boot

    Android Verified Boot 验证程序用来保护用户使用软件在设备上运行的完整性 它通常从设备固件的只读部分开始 xff0c 该部分加载代码并仅在密码验证代码是真实的且没有任何已知的安全缺陷之后执行 AVB是经过验证的引导的一种
  • Android快速编译镜像

    make bootimage 编译bootimagemake vendorimage编译 vendorimagemake dtboimagedtbo ninja快速编译系统 xff08 前提是编译部分的Android mk没有改变 xff0
  • nuttx-概述

    早期基于MSP430系列 STM32系列 EFM32系列 AT91SAM9X imx6ul系列做各种物联网产品 xff0c 近几年国芯片慢慢崛起 xff0c 加上ST芯片价格暴涨 xff0c 更是让国产芯片赢得了难得的发展机会 xff0c
  • nuttx-环境搭建

    尽管nuttx主要遵循Posix 和 ANSI 标准 xff0c 但是毕竟向下支持到了STM32F1系列的芯片 xff08 不带MMU xff09 xff0c 所以这个操作系统本质上还是一个微操作系统 下面从helloworld开始 官网
  • nuttx-第一个app demo

    应用开发 xff0c 与ucos freeRTOS等完全不一样 xff0c 看起来更像是linux的方式 xff0c os与app独立开发 xff0c 但是从单片机不具备MMU这一点就能判断出来 xff0c 假的就是假的 xff0c 即便是
  • nuttx-app的编译和执行原理

    首先阅读apps readme md Built In Applications NuttX also supports applications that can be started using a name string In thi