contiki学习笔记03

contiki学习笔记03

contiki是基于事件型驱动的操作系统,它传递事件的方式有两种,同步和异步。 process_post_synch函数是同步,调用它可以马上执行相关的线程;process_post是异步,调用它会产生一个事件,等待下次在主函数中执行;具体看代码:

void process_post_synch(struct process *p, process_event_t ev,
                        process_data_t data)
{
    /* 定义一个指针变量,用来存储当前线程的指针 */
    struct process *caller = process_current;
    /* 调用执行线程 */
    call_process(p, ev, data);
    /* 再赋值回来 */
    process_current = caller;
}

这边第一次看的时候有个地方不懂,为什么要保存当前的线程指针,看了call_process这个函数的实现方式后才懂,这个下面再说;同步传递事件的实现比较简单,就到此结束了。

现在来看下异步同步方式,contiki建了个数组,用来存储待处理的事件,nevents是还未处理的事件总数,fevent是下次将要处理的事件下标;

static process_num_events_t nevents, fevent;
static struct event_data events[PROCESS_CONF_NUMEVENTS];

其中event_data是自定义的事件类型,里面主要有3个成员,1是事件类型,2是数据指针,3是线程指针

struct event_data
{
    process_event_t ev;  /* typedef unsigned char process_event_t; */
    process_data_t data; /* typedef void *process_data_t; */
    struct process *p;
};

下面的代码就是异步的同步方式,虽然看起来有很多,但真正发挥作用的只有不到10行代码,它第一步先判断是后已经满了(在20行),如果已经满了则退出;否则就添加到数组里面去

int process_post(struct process *p, process_event_t ev, process_data_t data)
{
    /* 临时变量,用来标识当前要传递的事件放在哪里 */
    process_num_events_t snum;

    /* 当前没有其他线程在运行,换句话说当前传递者不是线程 */
    if (PROCESS_CURRENT() == NULL)
    {
        PRINTF("process_post: NULL process posts event %d to process '%s', nevents %d\r\n",
               ev, PROCESS_NAME_STRING(p), nevents);
    }
    else
    {
        PRINTF("process_post: Process '%s' posts event %02X to process '%s', nevents %d\r\n",
               PROCESS_NAME_STRING(PROCESS_CURRENT()), ev,
               p == PROCESS_BROADCAST ? "" : PROCESS_NAME_STRING(p), nevents);
    }

    /* 还未处理的线程总数已经满了(放不进来),退出 */
    if (nevents == PROCESS_CONF_NUMEVENTS)
    {
#if DEBUG

        if (p == PROCESS_BROADCAST)
        {
            printf("soft panic: event queue is full when broadcast event %02X was posted from %s\r\n",
                   ev, PROCESS_NAME_STRING(process_current));
        }
        else
        {
            printf("soft panic: event queue is full when event %02X was posted to %s from %s\r\n",
                   ev, PROCESS_NAME_STRING(p), PROCESS_NAME_STRING(process_current));
        }

#endif /* DEBUG */
        return PROCESS_ERR_FULL;
    }

    /* 计算下标,fevent是将要处理的事件下标,nevets是总为处理下标
    PROCESS_CONF_NUMEVENTS 是总的能存放为处理的事件总数 */
    snum = (process_num_events_t)(fevent + nevents) % PROCESS_CONF_NUMEVENTS;
    events[snum].ev = ev;
    events[snum].data = data;
    events[snum].p = p;
    /* 总数+1 */
    ++nevents;

    return PROCESS_ERR_OK;
}

这里面基本都好理解,比较难理解的是第41行了,snum = (process_num_events_t)(fevent + nevents) % PROCESS_CONF_NUMEVENTS;为什么下标可以这样计算:举个例子,PROCESS_CONF_NUMEVENTS最大是10,nevents目前是5,代表有5个未处理的事件,fevent目前已经处理到了第3个事件,即fevent目前等于3,这时候要把新的事件存在哪里呢?只能存在8这个位置,因为目前要处理的下标是3,还有5个事件待处理,所以只能存在8这个位置了,这个琢磨一下就能想通的。

contiki学习笔记03_第1张图片

你可能感兴趣的:(contiki)