process调用protothread机制的相关宏定义——用HelloWorld进程诠释

HelloWorld例子

#include "contiki.h"

#include <stdio.h> /* For printf() */
/*---------------------------------------------------------------------------*/
PROCESS(hello_world_process, "Hello world process");
AUTOSTART_PROCESSES(&hello_world_process);
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(hello_world_process, ev, data)
{
  PROCESS_BEGIN();

  printf("Hello, world\n");

  PROCESS_END();
}

PROCESS

#if PROCESS_CONF_NO_PROCESS_NAMES//是否字符串名字?
#define PROCESS(name, strname)                \
  PROCESS_THREAD(name, ev, data);            \//声明进程执行实体函数
  struct process name = { NULL,                                          process_thread_##name }//定义进程结构体变量name
#else
#define PROCESS(name, strname)                \
  PROCESS_THREAD(name, ev, data);              struct process name = { NULL, strname,                                  process_thread_##name }
#endif

PROCESS_THREAD(name, ev, data);一步一步展开之后为:

#define PROCESS_THREAD(name, ev, data)                 static PT_THREAD(process_thread_##name(struct pt *process_pt,                           process_event_t ev,                           process_data_t data))

PT_THREAD看protothread机制

static char process_thread_hello_world_process(struct pt *process_pt, process_event_t ev, process_data_t data);

这条语句相当于声明一个函数process_thread_hello_world,而这个函数就是进程执行实体函数。在后续的定义进程结构体可以看出。

进程结构体:

struct process {
  struct process *next;//指向下个进程结构体,在进程链表中使用
#if PROCESS_CONF_NO_PROCESS_NAMES//配置进程字符串名字?
#define PROCESS_NAME_STRING(process) ""//没有,空
#else
    //有字符串名字
  const char *name;//定义进程字符串名字
#define PROCESS_NAME_STRING(process) (process)->name//取名字
#endif
  PT_THREAD((* thread)(struct pt *, process_event_t, process_data_t));//进程执行实体函数
  struct pt pt;//pt结构体,存储实体函数阻塞时的位置
  unsigned char state, needspoll;//state是进程状态,needspoll标志进程是否需要优先执行
};
struct process hello_world_process = { NULL, strname, \                       process_thread_hello_world_process }

后边的的语句定义了一个process变量hello_world_process,并赋初值,为简化这里按有strname来处理。

总之,PROCESS宏定义,有两个功能,声明进程执行实体函数定义进程结构体变量,如下所示:

static char process_thread_hello_world_process(struct pt *process_pt, process_event_t ev, process_data_t data);
struct process hello_world_process = { NULL, strname, \
                      process_thread_hello_world_process }

注:这里只需要抓住hello_world_process变量,就抓住了整个进程。

AUTOSTART_PROCESSES

全部展开:

AUTOSTART_PROCESSES(&hello_world_process);

#if ! CC_NO_VA_ARGS
#if AUTOSTART_ENABLE
#define AUTOSTART_PROCESSES(...)                    struct process * const autostart_processes[] = {__VA_ARGS__, NULL}
#else /* AUTOSTART_ENABLE */
#define AUTOSTART_PROCESSES(...)                    extern int _dummy
#endif /* AUTOSTART_ENABLE */
#else
#error "C compiler must support __VA_ARGS__ macro"
#endif

这里用到C99 支持可变参数宏的特性,如:#define debug(…) printf(__VA_ARGS__) ,缺省号代表一个可以变化的参数表,宏展开时,实际的参数就传递给 printf()了。例:debug("Y = %d\n", y); 被替换成printf("Y = %d\n", y)【参考http://blog.chinaunix.net/uid-9112803-id-2898026.html

为了简洁,我们这里按有AUTOSTART_ENABLE来分析

最终展开为:

struct process * const autostart_processes[] = {&hello_world_process, NULL};

hello_world_process是上边声明的process结构体变量,所以AUTOSTART_PROCESSES(&hello_world_process)就是定义了一个数组,这个数组定义了要自启动的进程的process结构体变量指针。

我们用一个例子来说明,进程是怎么自启动的。

源代码$contiki$\platform\stm32test\contiki-main.c

int
main()
{
  dbg_setup_uart();
  printf("Initialising\n");

  clock_init();
  process_init();
  process_start(&etimer_process, NULL);
  autostart_start(autostart_processes);
  printf("Processes running\n");
  while(1) {
    do {
    } while(process_run() > 0);
    idle_count++;
    /* Idle! */
    /* Stop processor clock */
    /* asm("wfi"::); */
  }
  return 0;
}

可以看到,主函数在进行一系列初始化之后,启动etimer_process进程,然后启动需要自启动的进程。

我们进一步展开autostart_start函数,其中autostart_processes是上边声明定义的一个数组。

void
autostart_start(struct process * const processes[])
{
  int i;

  for(i = 0; processes[i] != NULL; ++i) {
    process_start(processes[i], NULL);
    PRINTF("autostart_start: starting process ‘%s‘\n", processes[i]->name);
  }
}

可以看到依次启动autostart_processes数组中的各个指针所对应的进程,这里的process_start等函数,后续再深究。

PROCESS_THREAD

PROCESS_THREAD(hello_world_process, ev, data)
{
   ……
}
static char process_thread_hello_world_process(struct pt *process_pt, process_event_t ev, process_data_t data){  ……}

这里的PROCESS_THREAD是定义进程执行主体函数,跟上边的不一样,上边的是声明这样一个函数。

总之,PROCESS_THREAD有两个作用:声明或者定义进程执行主体函数

使用protothread机制的宏定义

PROCESS_BEGIN

#define PROCESS_BEGIN()             PT_BEGIN(process_pt)

其中process_pt是进程执行主体传进来的参数 struct pt *process_pt。protothread机制

这个是进程开始的标志。

PROCESS_END

#define PROCESS_END()               PT_END(process_pt)

进程结束标志。

注:进程执行主体语句要放在PROCESS_BEGIN和PROCESS_END之间,不然会有不确定的错误发生。

PROCESS_WAIT_EVENT

#define PROCESS_WAIT_EVENT()        PROCESS_YIELD()

进程执行实体函数返回PT_YIELD,然后等待任一事件(进程是由事件驱动的)的到来,重新回到进程执行主体函数上次阻塞的位置,又继续执行后续的语句。

注:由protothread机制知,每次执行进程实体函数时,都会运行到PROCESS_BEGIN,然后才跳转。

PROCESS_WAIT_EVENT_UNTIL

#define PROCESS_WAIT_EVENT_UNTIL(c) PROCESS_YIELD_UNTIL(c)

等待一个事件,并附加条件c

PROCESS_YIELD

#define PROCESS_YIELD()             PT_YIELD(process_pt)

YIELD(放弃执行权)

PROCESS_YIELD_UNTIL

#define PROCESS_YIELD_UNTIL(c)      PT_YIELD_UNTIL(process_pt, c)

YIELD直到条件c成立

PROCESS_WAIT_UNTIL

#define PROCESS_WAIT_UNTIL(c)       PT_WAIT_UNTIL(process_pt, c)

一直等待,直到条件c

PROCESS_WAIT_WHILE

#define PROCESS_WAIT_WHILE(c)       PT_WAIT_WHILE(process_pt, c)

当条件c,等待

PROCESS_EXIT

#define PROCESS_EXIT()              PT_EXIT(process_pt)

进程退出

PROCESS_PT_SPAWN

#define PROCESS_PT_SPAWN(pt, thread)   PT_SPAWN(process_pt, pt, thread)
#define PT_SPAWN(pt, child, thread)          do {                            PT_INIT((child));                    PT_WAIT_THREAD((pt), (thread));          } while(0)

生产一个子进程,并阻塞住直到子进程执行完毕,再继续后边程序的执行。

注:这里要明确一个概念,进程是由事件驱动的,只有当有事件发生时,进程执行实体函数才会开始执行,也就是说一旦发生阻塞,执行实体函数返回并退出,那么只有事件来了,才会再次进入进程执行实体函数,执行完PROCESS_BEGIN后跳转到阻塞位置,判断是否继续阻塞。

HelloWorld例子展开代码

GCCc语言拓展实现版

#include "contiki.h"

#include <stdio.h> /* For printf() */

static char process_thread_hello_world_process(struct pt *process_pt, process_event_t ev, process_data_t data);
struct process hello_world_process = { NULL, "Hello world process", process_thread_hello_world_process };
struct process * const autostart_processes[] = {&hello_world_process, NULL};
static char process_thread_hello_world_process(struct pt *process_pt, process_event_t ev, process_data_t data)
{
  {
    char PT_YIELD_FLAG = 1;
    if (PT_YIELD_FLAG) {;}
    do {
                if(s != NULL) {
                  goto *s;
                }
       } while(0)

    printf("Hello, world\n");

    
    PT_YIELD_FLAG = 0;
    PT_INIT(pt);
    return PT_ENDED;
  }
  
}                                

switch语句实现版

#include "contiki.h"

#include <stdio.h> /* For printf() */

static char process_thread_hello_world_process(struct pt *process_pt, process_event_t ev, process_data_t data);
struct process hello_world_process = { NULL, "Hello world process", process_thread_hello_world_process };

struct process * const autostart_processes[] = {&hello_world_process, NULL};

static char process_thread_hello_world_process(struct pt *process_pt, process_event_t ev, process_data_t data)
{
  {
    char PT_YIELD_FLAG = 1;
    if (PT_YIELD_FLAG) {;} 

    switch(s) {
                case 0:

      printf("Hello, world\n");

    }
    PT_YIELD_FLAG = 0;
    PT_INIT(pt);
    return PT_ENDED;
  }
  
}
时间: 2024-10-07 11:44:12

process调用protothread机制的相关宏定义——用HelloWorld进程诠释的相关文章

Unity3D 多平台_预编译相关宏定义

预编译 原文地址:http://docs.unity3d.com/Documentation/Manual/PlatformDependentCompilation.html 平台定义     UNITY_EDITOR 编辑器调用. UNITY_STANDALONE_OSX 专门为Mac OS(包括Universal,PPC和Intelarchitectures)平台的定义. UNITY_DASHBOARD_WIDGET Mac OS Dashboard widget (Mac OS仪表板小部件

windows 下使用thread_create相关宏定义

#ifdef _WIN32 #include <windows.h> extern "C" {     extern int getopt(int, char * const *, const char *);     extern char *optarg; } #define PATHD '\\' typedef HANDLE thread_t; #define thread_create(thrp, attr, func, arg)                  

Unity 平台相关宏定义

Platform Defines Macros The platform defines that Unity supports for your scripts are:     UNITY_EDITOR Define for calling Unity Editor scripts from your game code. UNITY_STANDALONE_OSX Platform define for compiling/executing code specifically for Ma

UI控件相关宏定义

1.显示设置 1.1 view圆角和边框 /** 设置view圆角和边框 */ #define kViewBorderRadius(View, Radius, Width, Color)[View.layer setCornerRadius:(Radius)];[View.layer setMasksToBounds:YES];[View.layer setBorderWidth:(Width)];[View.layer setBorderColor:[Color CGColor]] 1.2 设

QT跟VC++结合来进行插件的验证机制(遍历vtable,保证虚函数的个数一致,也可使用Q_INVOKABLE宏定义)

由于最近公司要开发一个以C++插件机制为主的,主要有一个问题就是C++的二进制兼容性的问题.一旦类使用虚函数,只要随便改动下增删查改下头文件的虚函数,就会导致程序在跑的时候进行乱跳,因为这个时候exe跟dll里面的vtable模型是不一致的 刚好程序是使用QT开发了,所以就用了两种方式来保证头文件一致才能进行程序的加载 1. 利用QT的MOC机制QT的MOC机制里面有一个Q_INVOKABLE的宏定义,可以让moc生成类成员函数的相关信息,然后利用QObject里面的method来获取对应的函数

Protothread 机制

一.概述 很多传感器操作系统都是基于事件驱动模型的,事件驱动模型不用为每个进程都分配一个进程栈,这对内存资源受限的无线传感器网络嵌入式系统尤为重要. 然而事件驱动模型不支持阻塞等待抽象语句,因此程序员通常用状态机来实现控制流,但这都很复杂. 例子:一个假想的MAC层协议 用状态机实现: 实现上述代码,需要先提炼出准确特定的状态state,上述代码有三个状态:ON.OFF.WAITING. 要提炼出这几个状态并不简单,而且状态机实现后的代码跟系统功能没有相互对应,可阅读性差. Contiki采用一

宏定义的黑魔法 - 宏菜鸟起飞手册

转载:https://onevcat.com/2014/01/black-magic-in-macro/ 宏定义在C系开发中可以说占有举足轻重的作用.底层框架自不必说,为了编译优化和方便,以及跨平台能力,宏被大量使用,可以说底层开发离开define将寸步难行.而在更高层级进行开发时,我们会将更多的重心放在业务逻辑上,似乎对宏的使用和依赖并不多.但是使用宏定义的好处是不言自明的,在节省工作量的同时,代码可读性大大增加.如果想成为一个能写出漂亮优雅代码的开发者,宏定义绝对是必不可少的技能(虽然宏本身

iOS开发ARC与MRC下单例的完整写法与通用宏定义

#import "XMGTool.h" /** * 1:ARC下的完整的单例写法:alloc内部会调用+(instancetype)allocWithZone:(struct _NSZone *)zone方法,所以重写该方法,用GCD一次性函数,默认是线程安全的加了一把锁,也可以自己去加锁 @synchronized(self) { if (_instance == nil) { _instance = [super allocWithZone:zone]; } } 2:还要考虑cop

Linux的调用实现机制

朱秀秀) + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://www.cnblogs.com/“真实姓名(与最后申请证书的姓名务必一致)%20+%20原创作品转载请注明出处%20+%20<Linux内核分析>MOOC课程http:/mooc.study.163.com/course/USTC-1000029000%20” 本文转自http://blog.chinaunix.net/uid-20321537-id-1966859.html,在此表示感谢!