1. 程式人生 > >AliOS-Things--非同步事件框架Yloop (5)

AliOS-Things--非同步事件框架Yloop (5)

Yloop概要

 Yloop是AliOS Things的非同步事件框架。Yloop借鑑了,libuv及嵌入式業界常見的event loop,綜合考慮使用複雜性,效能,及footprint,實現了一個適合於MCU的事件排程機制。

Yloop上下文

 每個Yloop例項(aos_loop_t)與特定的任務上下文繫結,AliOS Things的程式入口application_start所在的上下文與系統的主Yloop例項繫結,該上下文也稱為主任務。主任務以外的任務也可以建立自己的Yloop例項。

Yloop排程

Yloop實現了對IO,timer,callback,event的統一排程管理:

  • IO:最常見的是Socket,也可以是AliOS Things的vfs管理的裝置
  • timer:即常見的定時器
  • callback:特定的執行函式
  • event:包括系統事件,使用者自定義事件

當呼叫aos_loop_run後,當前任務將會等待上述的各類事件發生。

Yloop實現原理

 Yloop利用協議棧的select介面實現了對IO及timer的排程。AliOS Things自帶的協議棧又暴露一個特殊的eventfd介面,Yloop利用此介面把VFS的裝置檔案,和eventfd關聯起來,實現了對整個系統的事件的統一排程。

Yloop的使用

/*
 * Copyright (C) 2015-2017 Alibaba Group Holding Limited
 */

#include
<aos/aos.h>
static void app_delayed_action(void *arg) { LOG("helloworld %s:%d %s\r\n", __func__, __LINE__, aos_task_name()); aos_post_delayed_action(5000, app_delayed_action, NULL); } int application_start(int argc, char *argv[]) { LOG("application started."); aos_post_delayed_action
(1000, app_delayed_action, NULL); aos_loop_run(); return 0; }

application_start裡面做了兩件事情:

  • 呼叫aos_post_delayed_action建立了一個1秒的定時器(Yloop裡面只有oneshot timer)
  • 呼叫aos_loop_run進入事件迴圈

1秒後,定時器觸發,app_delayed_action被呼叫,而app_delayed_action裡面

  • 呼叫LOG列印
  • 再次建立一個5秒的定時器,重而實現定期執行app_delayed_action

這裡注意到,程式並不需要aos_loop_init()去建立Yloop例項,因為系統會預設自動建立主Yloop例項。

與Socket的結合

以mqtt的framework/connectivity/mqtt/mqtt_client.c作為例子:

static int iotx_mc_connect(iotx_mc_client_t *pClient) 
{ 
	rc = MQTTConnect(pClient); 
	aos_poll_read_fd(get_ssl_fd(), cb_recv, pClient);
}

 在和服務端建立好socket連線後,呼叫aos_poll_read_fd()把mqtt的socket加入到Yloop的監聽物件裡。當服務端有資料過來時,cb_recv回撥將被呼叫,進行資料的處理。這樣,mqtt就不需要一個單獨的任務來處理socket,從而節省記憶體使用。同時,由於所有處理都是在主任務進行,不需要複雜的互斥操作。

系統事件的處理

AliOS Things定義了一系列系統事件,程式可以通過aos_register_event_filter()註冊事件監聽函式,進行相應的處理,比如WiFi事件。

static void netmgr_events_executor(input_event_t *eventinfo, void* priv_data) 
{
	switch((eventinfo->code)
	{
		case CODE_WIFI_ON_CONNECTED: 
			// do something
	} 
}

aos_register_event_filter(EV_WIFI, event_cb, NULL);

EV_USER以後的事件ID可以用於使用者自定義的事件。

Yloop回撥

 Yloop回撥用於跨任務的處理。以下面虛擬碼為例:

void do_uart_io_in_main_task( void* arg) 
{ 
	// dosomething
} 

void io_recv_data_cb( char c) 
{ 
	aos_schedule_call(do_uart_io_in_main_task, ( void*)( long)c); 
}

 假設uart_recv_data_cb是IO裝置收到資料時的回撥,收到資料後通過aos_schedule_call把實際處理do_uart_io_in_main_task放到主任務上下文去執行。這樣,資料的邏輯處理do_uart_io_in_main_task就不需要考慮併發,而去做複雜的互斥操作。

注意事項

 Yloop的API(include/aos/yloop.h)除了下述API,都必須在Yloop例項所繫結的任務的上下文執行:

  • aos_schedule_call
  • aos_loop_schedule_call
  • aos_loop_schedule_work
  • aos_cancel_work
  • aos_post_event

小結

 Yloop作為AliOS Things的事件框架,和VFS,協議棧深度結合,在取得較好的footprint的同時,能較好地適應於對footprint要求較高只有一個主任務的系統,也可以適用於對處理的併發性要求較高的系統。