nordic mesh 任務調度實現


nordic mesh 任務調度實現

nordic mesh的任務調度室基於定時器實現的,有兩個鏈表結構維護任務。

需要注意的是,任務調度的部分接口只能在“bearer event”的中段級別被調用,因此調用的形式是通過設置"bearer event"事件來實現的。

結構及接口 @timer_scheduler.h

任務調度的結構定義如下:


typedef enum
{
    TIMER_EVENT_STATE_UNUSED,      /**< Not present in the scheduler */
    TIMER_EVENT_STATE_ADDED,       /**< Added for processing */
    TIMER_EVENT_STATE_QUEUED,      /**< Queued for firing */
    TIMER_EVENT_STATE_RESCHEDULED, /**< Rescheduled, but not resorted */
    TIMER_EVENT_STATE_ABORTED,     /**< Aborted, but still in the list */
    TIMER_EVENT_STATE_IGNORED,     /**< Aborted, but added for processing */
    TIMER_EVENT_STATE_IN_CALLBACK  /**< Currently being called */
} timer_event_state_t;

/**
 * Timer event structure for schedulable timers.
 */
typedef struct timer_event
{
    volatile timer_event_state_t state;     /**< Timer event state. */
    timestamp_t                  timestamp; /**< 定時器激發時間  */
	
    timer_sch_callback_t         cb;        /**< 定時器激發時的回調函數 */
    uint32_t                     interval;  /**< 周期事件的時間間隔,0時表示單次事件 */
    void *                       p_context; /**< 調用回調函數cb時傳入的參數 */
    struct timer_event*          p_next;    /**< 指向下一個事件結構的指針,構成鏈表 */
} timer_event_t;

相關的幾個接口如下:


/**
 * Initializes the scheduler module.
 * 在nrf_mesh_init()中被調用
 */
void timer_sch_init(void);

/**
 * Schedules a timer event.
 *
 * @warning This function must be called from @ref BEARER_EVENT "bearer event" IRQ level or lower.
 * 			該函數必須在BEARER_EVENT的中斷優先級上被調用
 * @warning The structure parameters must not be changed after the structure has been added to the
 *          scheduler, as this may cause race conditions. If a change in timing is needed, please use the
 *          @ref timer_sch_reschedule() function. If any other changes are needed, abort the event, change the
 *          parameter, and schedule it again.
 *
 * @param[in] p_timer_evt A pointer to a statically allocated timer event, which will be used as
 *                        context for the schedulable event.
 */
void timer_sch_schedule(timer_event_t* p_timer_evt);


/**
 * Aborts a previously scheduled event.
 *
 * @warning This function must be called from @ref BEARER_EVENT "bearer event" IRQ level or lower.
 *			該函數必須在BEARER_EVENT的中斷優先級上被調用
 * @param[in] p_timer_evt A pointer to a previously scheduled event.
 */
void timer_sch_abort(timer_event_t* p_timer_evt);

/**
 * Reschedules a previously scheduled event.
 *
 * @warning This function must be called from @ref BEARER_EVENT "bearer event" IRQ level or lower.
 *			該函數必須在BEARER_EVENT的中斷優先級上被調用
 * @param[in] p_timer_evt   A pointer to a previously scheduled event.
 * @param[in] new_timestamp When the event should time out, instead of the old time.
 */
void timer_sch_reschedule(timer_event_t* p_timer_evt, timestamp_t new_timestamp);

任務調度實現 @timer_scheduler.c

調度器中維護兩個任務鏈表p_headp_add_head,當有新的任務加入調度時,首先會加到p_add_head鏈表中,此時新任務的狀態會設置為"TIMER_EVENT_STATE_ADDED";之后在process_add_list()函數遍歷p_add_head鏈表,將其中狀態為"TIMER_EVENT_STATE_ADDED"的任務加入到第一個鏈表p_head中。定時器激發時會遍歷第一個鏈表,將其中滿足運行時間的事件運行。

調度器結構的定義如下:


typedef struct
{
    timer_event_t* p_head;
    timer_event_t* p_add_head;
    uint32_t dirty_events; /**< Events in the fire list that needs processing */
    uint32_t event_count;
} scheduler_t;

/**
* Static globals
*/
static volatile scheduler_t m_scheduler;	/**<調度器實體 */
static bearer_event_flag_t m_event_flag;	/**<bearer event 事件 */

需要注意的是,部分定時器接口是在”bearer event“的中斷優先級的被調用的。因此,定義了m_event_flag的全局變量,以產生bearer-event事件調用。

timer_sch_init()

調度器初始化函數的實現代碼如下,在其中首先將調度器實體全部歸零,然后注冊了一個bearer-event事件。

void timer_sch_init(void)
{
	// 調度器結構置零
    memset((scheduler_t*) &m_scheduler, 0, sizeof(m_scheduler));
	
	// 注冊一個bearer-event事件
	// 當調用函數 bearer_event_flag_set(m_event_flag) 時
	// 會產生bearer-event中斷,來調用flag_event_cb()回調函數
    m_event_flag = bearer_event_flag_add(flag_event_cb);
}

bearer-event事件回調函數


static bool flag_event_cb(void)
{
	/* 處理被污染的任務
	 * 被污染的任務要么直接移除
	 * 需要再次調度的,則加入到p_add_head鏈表中
	 */
    process_dirty_events();

    /* add all the popped events back in, at their right places. 
	 * 該函數遍歷第二個鏈表,將其中的新加的任務添加到第一個鏈表中
	 * 第一個鏈表的任務是根據運行時間排序的,從頭到尾運行時間越來越晚
	 * 即第一個鏈表的鏈表頭是最先運行的節點
	 */
    process_add_list();

	/* 激發定時器
	 * 遍歷第一個鏈表,一次運行到達運行時間的任務
	 * p_head依次后移
	 */
    fire_timers(timer_now());
	
	/* 
	 * 設置定時器函數下次激發時間
	 */
    setup_timeout(timer_now());

    return true;
}

timer_sch_schedule()函數實現如下:


// 任務加入調度時,首先是加入第二個任務鏈表中
void timer_sch_schedule(timer_event_t* p_timer_evt)
{
    NRF_MESH_ASSERT(p_timer_evt != NULL);
    NRF_MESH_ASSERT(p_timer_evt->cb != NULL);

    uint32_t was_masked;
    _DISABLE_IRQS(was_masked);
    p_timer_evt->p_next = NULL;
    add_to_add_list(p_timer_evt);
    _ENABLE_IRQS(was_masked);

    bearer_event_flag_set(m_event_flag);
}

timer_sch_abort()

終止某個任務


void timer_sch_abort(timer_event_t* p_timer_evt)
{
    NRF_MESH_ASSERT(p_timer_evt != NULL);
    uint32_t was_masked;
    _DISABLE_IRQS(was_masked);
    if (p_timer_evt->state == TIMER_EVENT_STATE_IN_CALLBACK)
    {
        p_timer_evt->state = TIMER_EVENT_STATE_UNUSED;
    }
    else if (p_timer_evt->state == TIMER_EVENT_STATE_ADDED)
    {
        p_timer_evt->state = TIMER_EVENT_STATE_IGNORED;
    }
    else if (p_timer_evt->state != TIMER_EVENT_STATE_UNUSED)
    {
        if (!is_dirty_state(p_timer_evt->state))
        {
            m_scheduler.dirty_events++;
        }
        p_timer_evt->state = TIMER_EVENT_STATE_ABORTED;
        bearer_event_flag_set(m_event_flag);
    }
    _ENABLE_IRQS(was_masked);
}

timer_sch_reschedule()

再次調度



void timer_sch_reschedule(timer_event_t* p_timer_evt, timestamp_t new_timeout)
{
    NRF_MESH_ASSERT(p_timer_evt != NULL);

    uint32_t was_masked;
    _DISABLE_IRQS(was_masked);
    /* The events in the added queue will reinsert themselves in the processing. */
    if (p_timer_evt->state == TIMER_EVENT_STATE_UNUSED ||
        p_timer_evt->state == TIMER_EVENT_STATE_IN_CALLBACK)
    {
        add_to_add_list(p_timer_evt);
    }
    else if (p_timer_evt->state == TIMER_EVENT_STATE_ADDED ||
             p_timer_evt->state == TIMER_EVENT_STATE_IGNORED)
    {
        p_timer_evt->state = TIMER_EVENT_STATE_ADDED;
    }
    else
    {
        /* Mark the rescheduled event as dirty, will be processed at the next opportunity. */
        if (!is_dirty_state(p_timer_evt->state))
        {
            m_scheduler.dirty_events++;
        }
        p_timer_evt->state = TIMER_EVENT_STATE_RESCHEDULED;
    }
    p_timer_evt->timestamp = new_timeout;
    bearer_event_flag_set(m_event_flag);
    _ENABLE_IRQS(was_masked);
}


免責聲明!

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



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