今天高興,多發個文章慶祝,呵呵1.fusion概述
Fusion是一個IPC-(inter process communication)核心模組。Fusion的哲學是,進程可以僅利用Fusion提供的primivites便可互相“speak”。任何進程可以申請建立primitive執行個體,所有通過一個ID關聯起來的Fusion進程都可訪問和使用這個執行個體。Fusion支援以下幾個primivites:
Ø call: 非同步(同步)調用其他進程;
Ø ref: 參考值
Ø reactor: 非同步事件分發
Ø skirmish: counting lock
Ø property: multi-level locking
Ø shmpool: 共用記憶體使用量管理
並提供/proc檔案系統供查看各個primivites的狀態。
若干基本概念:
world: fusion使用者操作和通訊的環境,供clients互相發現對方。比如,Fusion primitives依靠Worldwide ID供識別和使用。每個World有自己的裝置節點。Fusion允許多個world同時存在。
fusionee: 指World的參與者。使用者空間的每個應用程式進入World會獲得一個Fusion ID。一個應用程式獲得多個Fusion ID是可能的但不常見。這個Fusion ID用以“target”其他fusionee的控制代碼。每個world至多隻有一個fusionee作為Master,其他的fusionee作為Slave。
Fusion註冊為主裝置號為250的字元裝置,共有/dev/fusion0-7八個裝置節點。每個裝置節點代表一個獨立的Fusion World。
注意,DirectFB項目對fusion的ioctl API進行了封裝。
2.fusion API2.1 開啟裝置節點
int fd;
fd = open( "/dev/fusion/0", flags );
flags = O_RDWR; defaultvalue.
flags |= O_NONBLOCK;addthisforanon-blockingreadcall.
flags |= O_EXCL; addthistobethe Fusion MasterofthisWorld.
flags |= O_APPEND; addthistobea Fusion SlaveinthisWorld.
EBUSY requesttobe Master,butthis worldalready hasaFusion Master.
EINTR aninterruptoccurred.Nochanges were made.
ENOMEM insufficientkernel memory.
2.2 常用調用—注意沒有write 調用
int close( int fd );
ssize_t read( int fd, void *buf, size_t count );
int ioctl( int fd, int request, ... );
void *mmap( void *start, size_t length, int prot,int flags, int fd, off_t offset );
2.2.1 讀操作範例
char buf[BUF_SIZE]
char *buf_p = buf;
int fd = open("/dev/fusion/0", O_RDWR |O_NONBLOCK );
int len = read( fd, buf, BUF_SIZE );
while (buf_p < buf + len)
{
FusionReadMessage *header = (FusionReadMessage*)buf_p;
void *data = buf_p + sizeof(FusionReadMessage);
...handle message...
buf_p = data + ((header->msg_size + 3) &~3);
}
2.2.2 ioctl範例
int fd = open("/dev/fusion/0", O_RDWR |O_NONBLOCK );
FusionEnter enter;
...init enter.api...
ret = ioctl( fd, FUSION_ENTER, &enter );
...store fusion_id...
2.2.3 mmap調用
用來創立一塊共用地區。通常不超過一個核心頁4K大小。同樣的一段記憶體地區會映射到同一個World內的所有Fusionees。第一個mmap調用必須由Fusion Master發起。
2.2.3 傳回值
EINVALInputparameterout-of-range.
EFAULTKernelmemoryfault.
EINTRaninterruptoccurred.Nochangeswere made.
讀調用的額外傳回值:
EMSGSIZEIfthefirstmessagedoesnotfitinthebuffer.
EAGAINForanon-blockingread:nomessagesavailable.
mmap調用的額外傳回值:
EPERMFirstmmap notperformedby Fusion Master.
ENOMEMNokernel memoryleft.
2.3 ioctl調用2.3.1 FUSION_ENTER
ioctl( fd, FUSION_ENTER , FusionEnter )
typedef struct {
struct {
int major; /* [in] */
int minor; /* [in] */
} api;
FusionID fusion_id; /* [out] */
} FusionEnter;
開啟裝置節點後,利用此調用進入Fusion World。之後,才會獲得分配的唯一的控制代碼:Fusion ID。對所有的slaves,這個調用在Master調用FUSION_UNBLOCK ‘unblock’World之前會一直被‘block’--阻塞。
Major和minor對應關係如下:3.x、4.x、8.x分別對應DirectFB 1.0,1.2和大於1.2的版本。比如我目前的DirectFB-1.4.10-IR-GFX,對應的設定如下:
#define FUSION_API_MAJOR_REQUIRED 8
#define FUSION_API_MINOR_REQUIRED 0
正確調用後,fusion_id會被返回。This fusion_id isFUSION_ID_MASTER for the Master.
傳回值:
(除了0, EFAULT and EINTR)
ENOPROTOOPT:不支援的APIversion或者Master使用了不相容的API version。
2.3.2 FUSION_UNLOCK
供Fusion Master調用,用來unblock Fusion World,從而使得Slaves進入World。
傳回值:
(除了0, EFAULT and EINTR)
PERM :不是由 Fusion Master調用。
2.3.2 FUSION_KILL
typedef struct {
FusionID fusion_id;
int signal;
int timeout_ms;
} FusionKill;
用來對其他fusionees發送signal。
Fusion_id對應著目標fusionee。0 means all but ourself 。如果沒有與之相對的fusionee,此調用會返回success。
Signal是用來傳送的訊號,比如SIGTERM、SIGKILL等。
timeout_ms為超市毫秒數設定。-1表示不等待,0表示不限制,換句話說,一直等到至少一個fusionee被terminated。
傳回值:
(除了0, EFAULT and EINTR)
ETIMEDOUT:逾時。
2.3.3 FUSION_ENTRY_SET_INFO 和FUSION_ENTRY_GET_INFO
typedefstruct {
FusionType type;
int id;
char name[FUSION_ENTRY_INFO_NAME_LENGTH]; /* [in]or [out] */
} FusionEntryInfo;
為Skirmish, Property , Reactor , Ref ,Shmpool儲存或讀取humanreadable名字。這個名字只用在此ioctl調用和/proc檔案系統中。
2.3.4 FUSION_FORK
typedef struct {
FusionID fusion_id;
} FusionFork;
待定。
Perform a ’fork’ of shared memory pools , reactorsand local references.This will copy these entities from fusionee fusion_id to thecalling fusionee.Upon return, fusion_id holds the calling fusionee ID.
Return values are EFAULT or EINTRforfailure,0forsuccess.
2.3.5 FUSION_SEND_MESSAGE
typedef struct {
FusionID fusion_id;
int msg_id;
int msg_channel;
int msg_size;
const void *msg_data;
} FusionSendMessage;
向fusion_id對應的fusionee發送一個Fusion message。對方用read調用來接收此message。接收方可以通過此message解析出寄件者的ID。
Msg_id是使用者可自訂的msg ID。msg_channel是可選的channel號。Msg_size是msg負載大小[0,65536]。Msg_data指向負載資料,一定不可為空。
傳回值:
(除了0, EFAULTand EINTR)
EINVAL: msg_sizet太小(小於0);
EMSGSIZE: msg_sizet太大(大於65536);
ENOMEMkernel: 記憶體不夠,嘗試讓msg_size小一些;
2.4 IOCTL:CALL primitive
ioctl( fd, FUSION_CALL_NEW , FusionCallNew )
ioctl( fd, FUSION_CALL_EXECUTE , FusionCallExecute)
ioctl( fd, FUSION_CALL_RETURN , FusionCallReturn )
ioctl( fd, FUSION_CALL_DESTROY , int )
2.5 IOCTL:REFprimitive
2.6 IOCTL:SKIRMISHprimitive
2.7 IOCTL:PROPERTYprimitive
2.8 IOCTL:REACTORprimitive
Reactor 模式
2.9 IOCTL:SHMPOOLprimitive
摘抄自李先靜的筆記:
在傳統的DirectFB應用中,所有的應用程式都在一個進程中,在效能上,有一些優勢,然而一個應用程式不穩定會造成整個系統的不穩定。若採用C/S模型,無疑是重蹈XWidnow的覆轍,會喪失效能上的優勢。
所以DirectFB採用了另外一種方式,與C/S相區別,稱之為主從模型(Master/Slave)。它加了一個稱之為fusion的核心模組。Fusion是熔化的意思,多個應用程式在不的進程空間裡,通過這個核心模組通訊,在這裡,一切都溶為一體了。Master應用程式負責初始化一個稱為竟技場的東西,其它Slave應用程式可以加入或者退出竟技場。當Master退出時,則其它所有Slave都必須退出。
Fusion裡採用了Reactor模式,每個應用程式可以通過ioctl向reactor註冊事件處理器,當有事件發生時,reactor會把事件寫入到所註冊了的應用程式的fusion檔案描述符時,之後應用程式可以從fusion檔案描述符裡讀取到事件數目據。
當然,應用程式也可以通過ioctl發送事件給其它應用程式,reactor時會把事件分發給其它應用程式。
下面以觸控螢幕為例介紹筆時間點事件的過程:
1.初始化時,driver_open_device建立一個進程,掛在/dev/input/event0上,等待筆時間點事件。
2.初始化時,應用程式建立另外一個線程,掛在/dev/fusionN(不同的應用程式N值不同)上。
3.當有筆時間點事件時,通過函數調用dfb_input_dispatch-->fusion_reactor_dispatch->ioctl(FUSION_REACTOR_DISPATCH)把訊息丟給核心模組。
4.核心模組中的Reactor把事件數目據寫入到各個所註冊的事件處理器的/dev/fusionN裡。
5.應用程式從/dev/fusionN檔案中取得事件數目據,並調用應用程式內部的reactor處理函數,一般是IDirectFBEventBuffer_InputReact/IDirectFBEventBuffer_WindowReact兩個函數。
6.然後,在IDirectFBEventBuffer_InputReact/IDirectFBEventBuffer_WindowReact兩個函數中,調用IDirectFBEventBuffer_AddItem把事件加入到視窗的事件隊列中。
7.在應用程式的主線程中,就可以通過調用視窗的GetEvent函數從事件隊列中擷取事件了,最後,把擷取的事件分發到各個視窗事件處理函數中。
參考
1.http://www.directfb.com.cn/viewthread.php?tid=6
基於fusion的DirectFB訊息流程
轉載時請註明出處和作者連絡方式
作者連絡方式:李先靜 <xianjimli at hotmail dot com>
2. linux-fusion-8.2.0內建文檔