NuttX的学习笔记 7

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yt454287063/article/details/53397819
  • 继续 非标准的来自于 VxWorks 接口的实验

    这下好了,文档断层了,有点令我头疼,继续。
    下一个:

    task_init(struct tcb_s tcb, char *name, int priority, uint32_t *stack, uint32_t stack_size, maint_t entry, char const argv[])

    下面有介绍,其中用粗体明确表示 not recommended 。看样子我可以偷个懒了。下一个:

    task_activate(struct tcb_s *tcb)

    在下面依旧可以看到:not recommended 。下一个:

    task_activate(struct tcb_s *tcb)

    依旧是 not recommended 。继续:

    int task_delete(pid_t pid);

    这个函数与 task_create() 成对出现。那么可以拿来测试。上次文档结束后,我测试了父进程和子进程都 printf ,结果是:可以看到两个进程相互在屏幕上打印字符。那么下面测试,在父子进程都打印 20 次的过程中,父进程在打印到10次的时候调用上面的函数。看看结果如何。首先,都打印20次时的输出:
    (这里直接停止吧)测试后发现会出现错误。错误的缘由不明:

    nsh> hello_task 20
    hello_task_main:task_create return:536871960

    hello_task_main:Hello World 1 times
    hello_task_main:Hello World 2 times
    hello_task_main:Hello World 3 times
    hello_task_main:Hello World 4 times
    hello_task_main:Hello World 5 times
    hello_task_main:Hello World 6 times
    hello_task_main:Hello World 7 times
    print_hello:Hello World 1 times
    hello_task_main:Hello World 8 times
    print_hello:Hello World 2 times
    hello_task_main:Hello World 9 times
    print_hello:Hello World 3 times
    hello_task_main:Hello World 10 times
    print_hello:Hello World 4 times
    hello_task_main:task_delete return:0
    hello_task_main:Hello World 11 times
    hello_task_main:Hello World 12 times
    hello_task_main:Hello World 13 times
    hello_task_up_hardfault: PANIC!!! Hard fault: 40000000
    up_assert: Assertion failed at file:armv7-m/up_hardfault.c line: 171 taskt
    up_dumpstate: sp: 10001718
    up_dumpstate: stack base: 10000f78
    up_dumpstate: stack size: 000007ec
    up_dumpstate: ERROR: Stack pointer is not within the allocated stack
    up_registerdump: R0: 00000001 10001610 10001608 0ffc0d9a 00000000 00000008
    up_registerdump: R8: 00000000 00000000 00000000 00000000 00000000 100017f8
    up_registerdump: xPSR: 81000000 PRIMASK: 00000001 CONTROL: 00000000

    再试试当子进程结束后再 delete。
    还是一样报错。
    看样子闲的没事干还是不要用这个函数了。。下一个:

    task_restart(pid_t pid)

    在这里我发现一个奇怪的现象,输入2就可以运行,3就不行了。我开始怀疑是不是栈给的小了。去看一下,居然还是之前的768,我想768应该是小的可怜了。换成2048后可以运行3 和 4 但是不能运行 5。我觉得我可以肯定的是。之前出现错误一定是栈给的小了。但是出现的情况如下:子进程并不会因为 restart 重启。printf 再也没有执行。

  • 标准接口实验

    试验一下 exit() 的效果,发现并不好,连编译都不能过。看样子这个括号内还是要一个参数的。寻找一番,在 某个网站 上找到了参数 int code 的说明:

    The value of status may be 0, EXIT_SUCCESS, EXIT_FAILURE,

    原来是这样,参数填 EXIT_SUCCESS ,因为该宏定义就是 0。
    在打印到一半时调用 exit(EXIT_SUCCESS)。测试结果是,父进程的输出直接没了。这也算是成功了吧。但是理论上说,父进程停止了,子进程为什么还能够继续输出呢?这里我怀疑这个我叫了很久的子进程是单独进程,并没有和我说的所谓的父进程构成父子关系。看样子之后的称呼就要改一改了。就用函数名来代替好了。下一个:

    getpid(void);

    下一个就由两个进程同时输出自己的 pid 再各自的函数中加入

    printf("%s :pid = %d \n", argv[0], getpid());

    输出结果:

    nsh> hello_task
    hello_task :pid = 2
    print_hello :pid = 3
    nsh> hello_task 1
    hello_task :pid = 4
    hello_task :Hello World 1 times
    print_hello :pid = 5
    print_hello :Hello World 1 times
    print_hello :Hello World 2 times
    nsh>

    看到这里突然有些不明白了,每个函数末尾的 return EXIT_SUCCESS 没有能使任务退出么?替换为上次的 exit(EXIT_SUCCESS) 再次测试。相同的结果。这让我想到之前的task_delete() 再来试一下。意外的,之前出现的问题一个都没有了。
    测试代码如下:

     #include <nuttx/config.h>
     #include <stdio.h>
     #include <stdlib.h>
     #include <errno.h>
    
     #define CONFIG_EXAMPLES_HELLO_TASK_PRIORITY  SCHED_PRIORITY_DEFAULT
     #define CONFIG_EXAMPLES_HELLO_TASK_STACKSIZE 2048
    
    int str2num(const char *s) {
        int rt = 0;
        while (*s >= '0' && *s <= '9') {
            rt = rt * 10 + (*s - '0');
            s++;
        }
        return rt;
    }
    
    int print_hello(int argc, char *argv[]) {
    
        printf("%s: pid = %d \n", argv[0], getpid());
    
        if (argv[1] != NULL) {
            auto int i;
            for (i = 0; i < 100; ++i)
                printf("%s: Hello World %d times \n", argv[0], i + 1);
        }
    
        exit(EXIT_SUCCESS);
        return EXIT_SUCCESS;
    }
    
    int hello_task_main(int argc, char *argv[]) {
    
        pid_t ret;
    
        ret = task_create("print_hello", CONFIG_EXAMPLES_HELLO_TASK_PRIORITY,
        CONFIG_EXAMPLES_HELLO_TASK_STACKSIZE, print_hello, &argv[1]);
        if (ret < 0) {
            int errcode = errno;
            printf("%s: ERROR: Failed to start print_hello: %d\n", argv[0],
                    errcode);
            return EXIT_FAILURE;
        } else
            printf("%s: Started print_hello at PID=%d\n", argv[0], ret);
    
        if (argv[1] != NULL) {
            auto int i;
            auto int a;
            a = str2num(argv[1]);
            for (i = 0; i < a; ++i)
                printf("%s: Hello World %d times \n", argv[0], i + 1);
        }
    
        ret = task_delete(ret);
        printf("%s: Delete print_hello return:%d\n", argv[0], ret);
    
        exit(EXIT_SUCCESS);
        return EXIT_SUCCESS;
    }

    print_hello 进程本来会打印100次,但是 hello_task 会在自己打印完成时将 print_hello 删除。

    测试结果:

    nsh> hello_task 10
    hello_task: Started print_hello at PID=5
    hello_task: Hello World 1 times
    hello_task: Hello World 2 times
    hello_task: Hello World 3 times
    hello_task: Hello World 4 times
    hello_task: Hello World 5 times
    hello_task: Hello World 6 times
    hello_task: Hello World 7 times
    print_hello: pid = 5
    hello_task: Hello World 8 times
    print_hello: Hello World 1 times
    hello_task: Hello World 9 times
    print_hello: Hello World 2 times
    hello_task: Hello World 10 times
    print_hello: Hello World 3 times
    hello_task: Delete print_hello return:0
    nsh>

    结果很理想。完全达到预期的效果。下一组

  • 标准vfork和exec(v | l)接口

    vfork

    这里我查了很久,结果是这样的,调用这个函数,将会产生一个子进程。子进程和父进程拥有相同的代码,但是在调用后 vfork 在父子进程中的返回值不同。这个可能很难想象,待会用例子说明。

    execv

    这个函数将直接调用 指定路径下的程序并给予参数。事实上,目前 NuttX 的路径下面什么都没有,所以这个先跳过。在例程 elf 中可以搜索到该字符串。所以这里试着开启一下例程 elf 。。。。结果显而易见,出现大量错误。实在懒得看,先放着。

    execl

    那就只演示一下 vfork
    按照其返回两值,最简单的,用 printf 输出其值,代码如下:

     #include <stdio.h>
     #include <stdlib.h>
    
    int hello_task_main(int argc, char *argv[]) {
    
        pid_t ret;
        if ((ret = vfork()) < 0) {
            int errcode = errno;
            printf("%s: ERROR: Failed to vfork hello_task_main: %d\n", argv[0], ret);
            return EXIT_FAILURE;
        } else if (ret == 0) {
            pid_t ch_proc = getpid();
            printf("%s: im children process PID = %d\n", argv[0], ch_proc);
            exit(EXIT_SUCCESS);
        } else {
            pid_t fa_proc = getpid();
            printf("%s: im father process PID = %d\n", argv[0], fa_proc);
            exit(EXIT_SUCCESS);
        }
        return EXIT_SUCCESS;
    }

    实验结果:

    nsh> hello_task
    hello_task: im children process PID = 3
    hello_task: im father process PID = 2
    nsh>

    明显出现了两个进程,完成。下一组。

  • 标准posix_spawn接口实验

    在例程中,找到了posix_spawn Unit Test,开启这个例子。
    打开后,出现了 ROMFS ,想了想,把这个打开好了。找一下,在这里:

    File Systems/ROMFS file system

    开启它。
    回到 > Application Configuration > Examples 下,发现多了例子:ROMFS example 一并启用。
    错误,那就慢慢来,先开启 ROMFS example 。出现错误:

    Host executable genromfs not available in PATH
    You may need todownload in from http://romfs.sourceforge.net/

    原来是少了东西。去NuttX官网看看
    。。。
    这里我要纠正一个之前的错误。是关于 tools/README.txt 下第一段文档。当时这个没仔细看跳过了。但是万万没想到,我需要的 ROMFS 就在这里。按照指示, git buildroot

    git clone https://bitbucket.org/nuttx/buildroot

    注意路径,完成后 cd 进去。二话不说打开 README
    但是,我不得不说,这篇 README 并没有什么帮助。按照安装 Kconfig 的步骤,解压 buildroot/toolchain/genromfs/ 下的 genromfs-0.5.2.tar.gz 进入 make make install。然后再去编译NuttX。这回成功了。下载测试。
    出错了,但是还算可以。我越来越怀疑是不是该按文档的顺序来学。
    总之,这个测试失败了,目前有很多接口都卡在了文件系统上,因为目前文件系统没有可以运行的二进制文件。那只能继续前进了。


被这个搞得头疼。重开一篇。

猜你喜欢

转载自blog.csdn.net/yt454287063/article/details/53397819