MTKtask简单总结速成版.docx
《MTKtask简单总结速成版.docx》由会员分享,可在线阅读,更多相关《MTKtask简单总结速成版.docx(20页珍藏版)》请在冰点文库上搜索。
MTKtask简单总结速成版
MTKtask小结1
MTK的基本执行单元是task,
从操作系统的角度来理解,task有些像线程而不是进程,进程之间的地址空间是相互隔离
的,说白点就是进程之间的全局变量是不相互干扰的。
而线程之间则是用同一个地址空间,
MTK的task之间的地址空间也是共同的,也就是说在MTK编程里,定义了一个全局变量,
那么在任何一个task里面都能引用,(这里只是举个例子,在实际编程过程中最好不要用全局变量,实在没有办法避开,那么全局变量也要分模块化,进行封装)。
所以说,MTK的
task更像线程,
MTK用的是实时操作系统nucleus,是非抢占式操作系统,也就是当高优先级的task在运
行时,低优先级的task是得不到运行时间的,除非等高优先级的task因为种种原因挂起。
MTK还有一个跟task想关的概念叫module,它跟task之间的关系是:
一个task可以对应多个module。
task主要表示是一个执行单元,module主要是用于传递消息,在MTK中,消息传递是module为单位src_mod->des_mod,而不是以task为单位。
MTKtask小结2
虽然MTK手机,是featurephone(功能机),不像symbian6那样可以同时运行多个应用。
但
是MTK还是由许多task组成。
平时MTK的后台播放MP3就是由一个task完成的。
具体以后分析。
现在来看看MTK最主要的task,MMItask,MTK的应用程序都是在该task里
面运行,它有一整套开发MTK应用的framework。
先来看创建MMItask的函数
kal_boolmmi_create(comptask_handler_struct**handle)
{
/**/
/*LocalVariables*/
staticcomptask_handler_structmmi_handler_info=
{
MMI_task,/*taskentryfunction*/
MMI_Init,/*taskinitializationfunction*/
NULL,
NULL,/*taskresethandler*/
NULL,/*taskterminationhandler*/
};
/**/
/*CodeBody*/
/**/
*handle=&mmi_handler_info;
returnKAL_TRUE;
}这个函数的结构,是的结构体
MTK创建task的基本结构,系统初始化时,会调用该函数。
看里面
typedefstruct{kal_task_func_ptrtask_init_func_ptrtask_cfg_func_ptr
comp_entry_func;//task的入口函数comp_init_func;//task的初始化函数
compcfgfunc;//task的配置函数
task_reset_func_ptrcomp_reset_func;//task的重置函数
task_end_func_ptrcomp_end_func;//task的终止函数
}comptask_handler_struct;
task的入口函数是必须的,这个函数告诉系统,初始化完相应的task控制块后,就要进入
该函数来运行。
task初始化函数,是在进入task入口函数之前被调用,用来初始化可能需要的资源,可选。
task终止函数是,当task结束是要调用,用来释放资源,可选。
其他两个函数我也不清楚干什么,希望知道的共享下
先看MMItask的初始化函数.
MMI_BOOLMMI_Init(task_indx_typetask_indx)
{
//创建一个mutex(互斥体)
mmi_mutex_trace=kal_create_mutex("mmi_trace");
//这个是初始化2step按键,2step按键是指有一些按键具有半按下状态
//比如照相功能,按下一半进行聚焦,再按下一半拍照
mmi_frm_get_2step_keys();
//初始化timer。
L4InitTimer();
//初始化UI相关信息,里面有许多画点,图等函数
setup_UI_wrappers();
returnMMI_TRUE;
}
初始化函数比较简单。
下面来看MMI的入口函数,这个函数是整个MMI运行的核心。
//为了简单,删除了大部分宏控制程序
voidMMI_task(oslEntryType*entry_param)
{
MYQUEUEMessage;
oslMsgqidqid;
U32my_index;
U32count=0;
U32queue_node_number=0;
//获得task的外部消息队列id,通过这个id,获得别的task往MMItask发送的消息
//MMItask有两个消息,外部消息队列和内部消息队列
//夕卜部消息队列的消息不直接处理,只是简单的存放到内部消息队列,
//这样使内部消息队列的优先级稍微高一点
qid=task_info_g[entry_param->task_indx].task_ext_qid;
mmi_ext_qid=qid;
//初始化event处理函数,这个几个event必须在获得消息前就进行注册
//不然可能使得这个event丢弃。
具体event事件,下次介绍
InitEventHandlersBeforePower0n();
//进入task的while循环
//task的while
(1)循环使得这个task不会结束,只有挂起或者运行
while
(1)
{
{
//判断是否有key事件需要处理
if(g_keypad_flag==MMI_TRUE)
{
mmi_frm_key_handle(NULL);
}
//获得外部消息队列里,消息的个数
msg_get_ext_queue_info(mmi_ext_qid,&queue_node_number);
//如果没有任何消息需要处理(内部消息和外部消息都没有,同时也没有按键
需要处理)
//OsINumOfCircularQMsgs获得内部消息队列消息的个数
if((queue_node_number==0)&&(OsINumOfCircularQMsgs。
==0)&&
(g_keypad_flag==MMI_FALSE))
{
U8flag=0;
ilm_structilm_ptr;
//去外部消息队列里获得消息,这是一个阻塞函数,也就是说,如果外部消息队列里,
〃没有任何消息,那么这个task将被阻塞,或者说挂起,也就是不在运行,
//直到有消息到达,才会被唤醒,看过操作系统原理的,应该不难理解
这个意思和这个本质
OslReceiveMsgExtQ(qid,&Message);
〃如果有消息,获得task的index
OslGetMyTaskIndex(&my_index);
//设置该task的获得mod为MMImod.
OslStackSetActiveModulelD(my_index,MOD_MMI);
〃保存该消息,用于放入到内部队列
ilm_ptr.src_mod」d=Message.src_mod_id;
ilm_ptr.dest_mod_id=Message.dest_mod_id;
ilm_ptr.msg」d=Message.msg_id;
ilm_ptr.sap_id=Message.sap_id;
ilm_ptr.local_para_ptr=Message.local_para_ptr;
ilm_ptr.peer_buff_ptr=Message.peer_buff_ptr;
//放入内部队列
//这个内部队列是个简单的循环队列
flag=OslWriteCircularQ(&ilm_ptr);
//对timer消息进行特殊处理
if(Message.src_mod」d!
=MOD_TIMER)
{
hold_local_para(ilm_ptr.local_para_ptr);hold_peer_buff(ilm_ptr.peer_buff_ptr);OslFreeInterTaskMsg(&Message);
}
}
else
{
//把外部消息放入到内部消息mmi_frm_fetch_msg_from_extQ_to_circularQ();
}
//处理内部消息
count=OslNumOfCircularQMsgs();
while(count>0)
{
OslGetMyTaskIndex(&my_index);
OslStackSetActiveModulelD(my_index,MOD_MMI);
if(OslReadCircularQ(&Message))
{
CheckAndPrintMsgld((U16)(Message.msg」d));
//是否是wap的消息
//这里就体现了一个task可以对应多个mod
if(Message.dest_mod」d==MOD_WAP)
{
}
else
{
switch(Message.msg_id)
{
//timer消息具体看MTKtimer小结2
caseMSG」D_TIMER_EXPIRY:
{
kal_uint16msg_len;
〃处理stacktimer消息
EvshedMMITimerHandler(get_local_para_ptr(Message.oslDataPtr,&msg_len));
}
break;
〃开机消息
〃具体分析见后文
caseMSG_ID_MMI_EQ_POWER_ON_IND:
{
mmi_eq_power_on」nd_struct*p=(mmi_eq_power_on」nd_struct*)Message.oslDataPtr;
/*Toinitializedata/time*/
SetDateTime((void*)&(p->rtc_time));gdi_init();
g_pwr_context.PowerOnMMIStatus=
MMI_POWER_ON」NDICATION;
switch(p->poweron_mode)
{
casePOWER_ON_KEYPAD:
OslMemoryStart(MMI_TRUE);g_charbat_context.PowerOnCharger=0;g_pwr_context.PowerOnMode=POWER_ON_KEYPAD;
sizeof(LastDuration));
DTGetRTCTime(&StartUpTime);memset(&LastDuration,0,mmi_bootup_entry_disk_check();break;
casePOWER_ON_PRECHARGE:
casePOWER_ON_CHARGER_IN:
g_pwr_context.PowerOnMode=
p->poweron_mode;
InitializeChargingScr();
if(!
g_charbat_context.isChargerConnected)
{
QuitSystemOperation();
break;
casePOWER_ON_ALARM:
g_pwr_context.PowerOnMode=POWER_ON_ALARM;
gdi_layer_clear(GDI_COLOR_BLACK);
AlmlnitRTCPwron();
break;
casePOWER_ON_EXCEPTION:
g_pwr_context.PowerOnMode=POWER_ON_EXCEPTION;
gdi_layer_clear(GDI_COLOR_BLACK);OslMemoryStart(MMI_TRUE);
SetAbnormalReset();
InitializeAll();
OslDumpDataInFile();
ClearInputEventHandler(MMI_DEVICE_ALL);ClearKeyHandler(KEY_END,
KEY_LONG_PRESS);
InitNvramData();
InitAllApplications();
mmi_pwron_exception_check_display();break;
default:
break;
}
}
break;
//event时间,这个也是MMItask的一个重点
default:
ProtocolEventHandler(
(U16)Message.oslMsgId,(void*)Message.oslDataPtr,(int)Message.oslSrcld,(void*)&Message);
break;
}
}
OslFreeInterTaskMsg(&Message);
msg_get_ext_queue_info(mmi_ext_qid,&queue_node_number);
count--;
}
}
}
}
MMItask内容比较多,删除了一些代码,留下主要的骨干。
总体来看,1把外部消息放入内部消息队列
2处理各种消息,开机消息,按键消息和event机制注册的各种其他消息
MTKtask小结3
在MTKtask小结2中大概描述了下MMItask的工作方式:
从外部队列获取消息放入内部消息队列,内部消息队列根据消息类型注册的回调函数,进行调用(event机制,这个又
是MMIframework的主要部分之一)。
在MTK上,用户(开发人员)可以根据需要,创建task。
创建一个task分为4步:
1增加一个taskindex到custom_task_indx_type
2增加一个modindex至Ucustom_module_type
3把mod关联到相应的task上,因为一个task可以对应多个mod,所以需要把mod挂载到task上。
(用挂载这个词,应该就比较好理解了,task是MTK执行的基本单位,所以一个mod要能
独立运行,就要挂载到某个task上,为什么不一个mod—个task呢,我想task越多,多系
统效率影响就越大。
那么就可以考虑互斥的mod挂载到一个task上,反正互斥的,不会同
时需要运行,就像音乐,视频,照相机一样,不会同时运行)
4仓U建task基本信息至Ucustom_comp_config_tbl
下面来具体看一个例子。
1添加taskindex
typedefenum{
INDX_CUSTOM1=RPS_CUSTOM_TASKS_BEGIN,
INDX_CUSTOM2,
#ifdefTASK_CREATE_TEST
INDX_TASK_TEST,
#endif
RPS_CUSTOM_TASKS_END
}custom_task_indx_type;我们增加了一个taskindexINDX_TASK_TEST
2添加一个modindex
typedefenum{
MOD_CUSTOM1=MOD_CUSTOM_BEGIN,
MOD_CUSTOM2,
#ifdefTASK_CREATE_TEST
MOD_TASK_TEST,
#endif
MOD_CUSTOM_END
}custom_module_type;
我们增加了一个modindexMOD_TASK_TEST
3挂载mod到task上
custom_task_indx_typecustom_mod_task_g[MAX_CUSTOM_MODS]=
{
INDX_CUSTOM1,/*MOD_CUSTOM1*/
INDX_CUSTOM2,/*MOD_CUSTOM2*/
#ifdefTASK_CREATE_TEST
INDX_TASK_TEST,
#endif
INDX_NIL/*PleaseendwithINDX_NILelement*/
};
这样就把MOD_TASK_TEST挂载到INDX_TASK_TEST上面了,这里的映射关系是通过index来控制的,也就是说要的到MOD_TASK_TEST对应的taskindex,只要这样task
index=custom_mod_task_g[MOD_TASK_TEST];所以创建过程中,顺序一定要对应好,不然容易出错。
4创建task信息
constcomptask_info_structcustom_comp_config_tbl[MAX_CUSTOM_TASKS]=
{
/*INDX_CUSTOM1*/{"CUST1","CUST1Q",210,1024,10,0,
#ifdefCUSTOM1_EXIST
custom1_create,KAL_FALSE
#else
NULL,KAL_FALSE
#endif
},
/*INDX_CUSTOM2*/
{"CUST2","CUST2Q",211,1024,10,0,
#ifdefCUSTOM2_EXIST
custom2_create,KAL_FALSE
#else
NULL,KAL_FALSE
#endif
},#ifdefTASK_CREATE_TEST
/*INDX_TASK_TEST*/
{"TAST_TEST","TASK_TESTQ",212,1024,10,0,task_test_create,KAL_FALSE
},
#endif};
comp_create_func;//task仓U建函数
comp_internal_ram_stack;//是否是internal_ram_stack}comptask_info_struct;
task的优先级是数值越大,优先级越低。
由于是MTK用的是实时操作系统,高优先级的
task只要需要,就会先运行,一直运行,所以task的优先级定义时需要考虑清楚。
comp_internal_ram_stack表示是否使用internalramstack,internalram相对速度要快,但是数量很有限,一般自己创建的不要去使用,容易引起问题。
MTKtask小结4
在MTKtask小结3中写到创建一个MTKtask,没有写完,今天把剩下的写完。
下面需
要介绍创建task信息的函数。
kal_booltask_test_create(comptask_handler_struct**handle)
{
staticconstcomptask_handler_structtask_test_handler_info=
{
task_test_main,/*taskentryfunction*/
NULL,/*taskinitializationfunction*/
NULL,/*taskconfigurationfunction*/
NULL,/*taskresethandler*/
NULL,/*taskterminationhandler*/
};
*handle=(comptask_handler_struct*)&task_test_handler_info;
returnKAL_TRUE;
}
这个函数的结构是不是很眼熟,对,就是MTKtask小结2介绍MMItask创建函数
mmi_create,创建函数的格式都是一样的,具体结构体的说明就看MTKtask小结2,相
应的函数可以补充,简单期间就有一个入口函数,不过一般都够了。
voidtask_test_main(task_entry_struct*task_entry_ptr)
{
//消息实体
ilm_structcurrent_ilm;
//消息队列id
oslMsgqidqid=task_info_g[task_entry_ptr->task_indx].task_ext_qid;
//初始化一些信息,这里只会被执行一次
tast_test_init()
//进入消息循环
while
(1){
//接受消息,如果没有消息,挂起该task
receive_msg_ext_q(qid,¤t_ilm);
〃根据消息id处理各种消息
switch(current_ilm.msg_id){
caseMSG_ID_TASK_TEST_XX:
break;
default:
break;
}
free_ilm(¤t_ilm);
}
}
这样,一个task就建立完成了。
如果想给自己的task建立一个强大的timer功能,那么
就可以根据MTKtimer小结3里介绍的那样,建立一个eventschedulertimer,注意,这个stacktimer里的mod要写成MOD_TASK_TEST而不是MOD_MMI,这样
MSG_ID_TIMER_EXPIRY就会发送到这个task里面,只要进行相应的处理就ok了。
task之间的交互是通过消息来传递的,当然也可以通过全局变量,共享内存等等(这里不是
linux那样的共享内存,因为MTK里面,整个系统的地址空间只有一个,那么一个task里
的内存,可以被另一个task访问,只要知道地址,没有限制,具体可以看MTK内存管理
简单总结)。
只要自己控制好(互斥问题),还是比较灵活的。
比如想要在这个task里面处理按键事件,比较繁琐,先要在MMItask里面接受按键事件,然后根据自己定义的消息,把这个按键事件发送到这个task里面,这个task里面根据相应
的消息处理函数,分发处理。
一般来说,task做一些后台处理比较方便(跟io有关的),如果想实现并行(linux时间片那样系统自动切换task),那是不现实,