Contiki事件


一、事件相關數據結構

 

1、事件結構體

struct event_data {
  process_event_t ev;
  process_data_t data;
  struct process *p;
};

 

其中process_event_t和process_data_t的定義:

typedef unsigned char process_event_t;
typedef void *        process_data_t;

 所以event_data結構體中的ev是一個unsigned char型數據,標識事件的類型

 

(1)事件標識ev

其中0-127為用戶進程內使用,128-255用於不同進程之間的通信。

Event identifiers below 127 can be freely used within a user process, whereas event identifiers above 128 are intended to be used between different processes. Identifiers above 128 are managed by the kernel. The first numbers over 128 are statically allocated by the kernel, to be used for a range of different purposes. 

 

  • 系統定義的事件標識:
#define PROCESS_EVENT_NONE            0x80
#define PROCESS_EVENT_INIT            0x81
#define PROCESS_EVENT_POLL            0x82
#define PROCESS_EVENT_EXIT            0x83
#define PROCESS_EVENT_SERVICE_REMOVED 0x84
#define PROCESS_EVENT_CONTINUE        0x85
#define PROCESS_EVENT_MSG             0x86
#define PROCESS_EVENT_EXITED          0x87
#define PROCESS_EVENT_TIMER           0x88
#define PROCESS_EVENT_COM             0x89
#define PROCESS_EVENT_MAX             0x8a

 

PROCESS_EVENT_NONE : This event identifier is not used.

PROCESS_EVENT_INIT : This event is sent to new processes when they are initiated.

PROCESS_EVENT_POLL : This event is sent to a process that is being polled.

PROCESS_EVENT_EXIT : This event is sent to a process that is being killed by the kernel. The process may choose to clean up any allocated resources, as the process will not be invoked again after receiving this event.

PROCESS_EVENT_CONTINUE : This event is sent by the kernel to a process that is waiting in aPROCESS_YIELD() statement.

PROCESS_EVENT_MSG : This event is sent to a process that has received a communication message. It is typically used by the IP stack to inform a process that a message has arrived, but can also be used between processes as a generic event indicating that a message has arrived.

PROCESS_EVENT_EXITED : This event is sent to all processes when another process is about to exit. A pointer to the process control block of the process that is existing is sent along the event. When receiving this event, the receiving processes may clean up state that was allocated by the process that is about to exit.

PROCESS_EVENT_TIMER : This event is sent to a process when an event timer (etimer) has expired.

 

  • 最后一個事件標識lastevent

我們知道128-255用於不同進程之間的通信,lastevent用來記錄最后一個分配出去的事件標識,下個事件標識應該是lastevent加1。lastevent初始化為PROCESS_EVENT_MAX。

/*---------------------------------------------------------------------------*/
process_event_t
process_alloc_event(void)
{
  return lastevent++;
}

 

  lastevent = PROCESS_EVENT_MAX;

 

(2)事件數據

event_data是事件發生時,所攜帶的相關信息,其類型為指向void型的指針

 

(3)事件所要傳遞到的目的進程的指針

struct process *p;

p為指向這個事件所要傳遞到的進程的指針。

 在http://www.cnblogs.com/songdechiu/p/5801136.html我們知道,進程執行實體函數如下

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

 

進程是由事件驅動的,並采用了protothread機制。進程執行實體函數,三個參數,

struct pt *process_pt, process_event_t ev, process_data_t data

其中process_pt可以理解為lc,ev就是本次傳遞給本進程的事件標識,data為本次傳遞給本進程事件所攜帶的信息。

 

2、事件隊列

static struct event_data events[PROCESS_CONF_NUMEVENTS];
#define PROCESS_CONF_NUMEVENTS 32

 

這個事件隊列是由數組實現的循環隊列,默認最多可以存放32個事件。當超過32個事件后,從頭開始循環存儲。

大致示意圖:

 

 

參考百度百科

 

(1)事件總數nevents和隊列頭指針fevent

static process_num_events_t nevents, fevent;
typedef unsigned char process_num_events_t;

 

在do_event中可看出

/* Since we have seen the new event, we move pointer upwards
       and decrese the number of events. */
    fevent = (fevent + 1) % PROCESS_CONF_NUMEVENTS;
    --nevents;

 

nevents是需要處理的事件總數,也是隊列大小。

fevent是當前需要處理的事件在數組數組中的偏移,這里fevent相當於頭指針head

 

(2)process_maxevents

#if PROCESS_CONF_STATS
process_num_events_t process_maxevents;
#endif

 

#if PROCESS_CONF_STATS
  if(nevents > process_maxevents) {
    process_maxevents = nevents;
  }
#endif /* PROCESS_CONF_STATS */

 

process_maxevents為最多事件數,注意與PROCESS_CONF_NUMEVENTS區分,PROCESS_CONF_NUMEVENTS為隊列的最大容量

 

二、事件相關處理函數

 

1、process_nevents

int
process_nevents(void)
{
  return nevents + poll_requested;
}

返回需要處理的事件總數nevents和poll請求標志的和。進程分為兩種,協調式和搶占式。nevents代表需葯給協調式進程處理的事件,poll_requested代表需要給搶占式進程處理的事件。

 

2、非同步事件處理

非同步事件處理中,函數process_post先將事件放到事件隊列中。

事件處理函數do_event()再把事件傳遞給接收事件的進程。

 

(1)非同步事件傳遞函數process_post

int
process_post(struct process *p, process_event_t ev, process_data_t data)
{
  static process_num_events_t snum;

  if(PROCESS_CURRENT() == NULL) {//輸出調試信息
    PRINTF("process_post: NULL process posts event %d to process '%s', nevents %d\n",
       ev,PROCESS_NAME_STRING(p), nevents);
  } else {
    PRINTF("process_post: Process '%s' posts event %d to process '%s', nevents %d\n",
       PROCESS_NAME_STRING(PROCESS_CURRENT()), ev,
       p == PROCESS_BROADCAST? "<broadcast>": PROCESS_NAME_STRING(p), nevents);
  }
  
  if(nevents == PROCESS_CONF_NUMEVENTS) {//隊列已滿,返回錯誤信息RPOCESS_ERR_FULL
#if DEBUG
    if(p == PROCESS_BROADCAST) {
      printf("soft panic: event queue is full when broadcast event %d was posted from %s\n", ev, PROCESS_NAME_STRING(process_current));
    } else {
      printf("soft panic: event queue is full when event %d was posted to %s frpm %s\n", ev, PROCESS_NAME_STRING(p), PROCESS_NAME_STRING(process_current));
    }
#endif /* DEBUG */
    return PROCESS_ERR_FULL;
  }
  
  snum = (process_num_events_t)(fevent + nevents) % PROCESS_CONF_NUMEVENTS;//尾指針
  events[snum].ev = ev;
  events[snum].data = data;
  events[snum].p = p;
  ++nevents;//事件總數加1

#if PROCESS_CONF_STATS
  if(nevents > process_maxevents) {
    process_maxevents = nevents;//更新process_maxevents
  }
#endif /* PROCESS_CONF_STATS */
  
  return PROCESS_ERR_OK;//返回成功信息
}

 

這個函數就是把事件放到事件隊列中去。先判斷隊列是否已經滿,滿了就返回錯誤信息。沒滿則先找到尾指針,將事件添加到隊列尾部,返回成功信息。

 

(2)事件處理函數do_event

static void
do_event(void)
{
  static process_event_t ev;
  static process_data_t data;
  static struct process *receiver;
  static struct process *p;
  
  /*
   * If there are any events in the queue, take the first one and walk
   * through the list of processes to see if the event should be
   * delivered to any of them. If so, we call the event handler
   * function for the process. We only process one event at a time and
   * call the poll handlers inbetween.
   */

  if(nevents > 0) {//有事件需要處理,取出第一個事件
    
    /* There are events that we should deliver. */
    ev = events[fevent].ev;
    
    data = events[fevent].data;
    receiver = events[fevent].p;

    /* Since we have seen the new event, we move pointer upwards
       and decrese the number of events. */
    fevent = (fevent + 1) % PROCESS_CONF_NUMEVENTS;//頭指針后移
    --nevents;//事件總數減1

    /* If this is a broadcast event, we deliver it to all events, in
       order of their priority. */
    if(receiver == PROCESS_BROADCAST) {//廣播事件?
      for(p = process_list; p != NULL; p = p->next) {//遍歷所有進程

    /* If we have been requested to poll a process, we do this in
       between processing the broadcast event. */
    if(poll_requested) {//在此期間,如果有搶占式進程需要執行,則先執行搶占式進程
      do_poll();
    }
    call_process(p, ev, data);//沒有的話,將事件依次傳給所有進程
      }
    } else {//不是廣播事件
      /* This is not a broadcast event, so we deliver it to the
     specified process. */
      /* If the event was an INIT event, we should also update the
     state of the process. */
      if(ev == PROCESS_EVENT_INIT) {//初始化事件?
    receiver->state = PROCESS_STATE_RUNNING;//設置狀態,這個狀態是就緒狀態
      }

      /* Make sure that the process actually is running. */
      call_process(receiver, ev, data);//傳遞事件給特定進程
    }
  }
}

 

這個函數最終就是調用call_process函數,將事件傳遞給特定進程。進程執行主體函數開始執行。

 

3、同步事件處理

 

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;//恢復當前進程指針
}

 

 同步事件處理中,事件立馬就傳遞給了特定的進程,表現為立馬執行ProcessB的執行實體函數。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM