vxworks源码剖析- 数据结构篇一
来源:互联网 发布:网络摄影机三星 编辑:程序博客网 时间:2024/05/20 18:17
http://commoncosmos.blog.163.com/blog/static/186295315201281185449565/
vxworks中使用了多种基本数据结构,例如双向链表,队列,树等等,本文将介绍这些基本数据结构在vxworks中的实现。
1. 双向链表
双向链表是最简单的数据结构,其实现也非常简单;而且,双向链表往往是实现其他数据结构的基础,因此本文最先介绍双向链表。双向链表的定义在dllLib.h文件中,函数实现在dllLib.c文件中。
在介绍双向链表之前,有必要先介绍一下vxworks中双向链表的实现样式:
List为一个指针,该指针链表结构体,包含两个域,分别指向链表头节点和尾节点:
typedef struct
{
DL_NODE *head;
DL_NODE *tail;
} DL_LIST;
head和tail指针分别指向链表的头节点和尾节点,节点结构体包含两个域,分别为前一个节点和后一个节点,节点结构体的定义为:
typedef struct dlnode
{
struct dlnode *next;
struct dlnode *previous;
} DL_NODE;
1.1 双向链表创建
在创建链表时,链表还没有任何子节点,因此此时的头节点和尾节点指针均为NULL;但是链表结构体需要创建,因此需要为链表结构体分配内存,创建链表代码如下:
DL_LIST *dllCreate (void)
{
FAST DL_LIST *pList = (DL_LIST *) malloc ((unsigned) sizeof (DL_LIST));
dllInit (pList);
return (pList);
}
STATUS dllInit
(
FAST DL_LIST *pList /* #define FAST register */
)
{
pList->head = NULL;
pList->tail = NULL;
return (OK);
}
此时创建的链表结构只有一个链表头,但是还没有任何节点:
1.2 添加节点
vxworks中的双向链表的节点都是添加在链表的尾部,通过的dllAdd函数实现,而dllAdd函数通过调用dllInsert函数来实现,dllInsert函数实现具体的添加过程;链表节点的添加主要通过一些指针的迁移来完成,在添加过程中需要注意中间节点的存储,并注意指针迁移顺序,最重要的是千万要保证链表不能断链,说了这么多,不如看代码实在:
void dllAdd
(
DL_LIST *pList, /* pointer to list descriptor */
DL_NODE *pNode /* pointer to node to be added */
)
{
dllInsert (pList, pList->tail, pNode);
}
void dllInsert
(
FAST DL_LIST *pList, /* pointer to list descriptor */
FAST DL_NODE *pPrev, /* pointer to node after which to insert */
FAST DL_NODE *pNode /* pointer to node to be inserted */
)
{
FAST DL_NODE *pNext;
if (pPrev == NULL)
{ /* new node is to be first in list */
pNext = pList->head;
pList->head = pNode; /*1.设置链表结构体的头指针*/
}
else
{ /* make prev node point fwd to new */
pNext = pPrev->next;
pPrev->next = pNode; /*2.将节点添加到添加处节点的后面*/
}
if (pNext == NULL)
pList->tail = pNode; /*3.设置链表结构体的尾指针*/
else
pNext->previous = pNode; /*4.将节点添加到添加处节点的后面节点的前面*/
/* set pointers in new node */
pNode->next = pNext; /*5.设置节点的后向指针*/
pNode->previous = pPrev; /*6.设置节点的前向指针*/
}
双向链表的添加,需要分三种情况:
1.2.1 链表中无节点
链表刚创建时就是类似的情况,此时链表结构体的头指针和尾指针均指向NULL;这种情况下添加节点主要是执行代码中的1、3、5、6语句,可以用下图表示:
1.2.2 链表中有1个节点
当链表中有1个节点时,链表结构体的头指针和尾指针均指向该节点,但是该节点的前向和后向指针则为NULL,此时添加节点主要执行代码中的2、3、5、6语句,具体操作可以用下图演示:
1.2.3 链表中节点个数大于1个
如果链表中的节点个数大于1个的时候,就可以在这两个节点中间插入节点了,不过采用dllAdd函数是无法实现的,因为这个函数每次都是在链表的最后一个节点处添加节点的,因此执行的语句仍然是2、3、5、6,和前面一种情况是一样的;要实现往两个节点中间插入节点,只能通过dllInsert函数来实现,这种方式插入节点不需要改变链表结构体的头指针和尾指针,只需要改变节点的前向和后向指针就可以了,执行的语句为2、4、5、6,可以用下图来演示:
1.2.4 在链表头部添加节点
当链表中没有节点时,在链表头部添加节点和第一种情况是完全一样的,执行1、3、5、6语句;如果链表中有节点时,需要改变链表头指针的位置,执行的语句为1、4、5、6,具体情况和上面大同小异:
1.3 删除节点
节点的删除相对于节点的添加来说,要相对容易一些,因为节点的删除只需要改变两个指针即可;不过和添加节点相同的是,删除节点也需要考虑四种情况,具体代码如下:
void dllRemove
(
DL_LIST *pList, /* pointer to list descriptor */
DL_NODE *pNode /* pointer to node to be deleted */
)
{
if (pNode->previous == NULL)
pList->head = pNode->next; /*1.改变链表的头指针*/
else
pNode->previous->next = pNode->next; /*2.改变待删除节点的前向节点的后向指针*/
if (pNode->next == NULL)
pList->tail = pNode->previous; /*3.改变链表的尾指针*/
else
pNode->next->previous = pNode->previous; /*4.改变待删除节点的后向节点的前向指针*/
}
1.3.1 删除节点为链表中唯一的一个节点
此时链表中的节点既是链表的第一个节点,也是最后一个节点,因此,删除该节点后,链表中没有节点,链表的头指针和尾指针均为NULL;此种情况下,执行的语句为1、3,具体演示如下:
1.3.2 链表中节点数大于1个,删除节点为链表的第一个节点
删除节点为链表的第一个节点,链表的尾指针将不会发生变化,头指针指向待删除节点的下一个节点,而待删除节点的后向节点的前向指针将为NULL,执行语句为1、4,具体演示如下:
1.3.3 链表中节点数大于1个,删除节点为链表的最后一个节点
删除节点为链表的最后一个节点,链表的头指针不会发生变化,尾指针指向待删除节点的前向节点,而待删除节点的前向节点的后向指针将为NULL,执行语句为2、3,具体演示如下:
1.3.4 链表中节点数大于2个,删除节点为链表中间的一个节点
此种情况最简单,只需要改变待删除节点的前向节点的后向指针和后向节点的前向指针,将待删除节点的前向节点和后向节点连接起来即可,执行语句为2、4,具体演示如下:
1.4 获取首节点
获取首节点通过dllGet函数实现,主要完成两个功能:删除首节点,返回首节点;删除首节点和删除节点功能基本相似,主要是前面描述的1.3.1和1.3.2描述的情况,至于返回首节点就更加简单了:
DL_NODE *dllGet
(
FAST DL_LIST *pList /* pointer to list from which to get node */
)
{
FAST DL_NODE *pNode = pList->head;
if (pNode != NULL) /* is list empty? */
{
pList->head = pNode->next; /* make next node be 1st */
if (pNode->next == NULL) /* is there any next node? */
pList->tail = NULL; /* no - list is empty */
else
pNode->next->previous = NULL; /* yes - make it 1st node */
}
return (pNode);
}
1.5 获取节点数目
获取节点数目通过dllCount函数实现,并结合DLL_NEXT宏实现,DLL_NEXT定义如下:
#define DLL_NEXT(pNode) \
( \
(((DL_NODE *)(pNode))->next) \
)
dllCount函数实现如下:
int dllCount
(
DL_LIST *pList /* pointer to list descriptor */
)
{
FAST DL_NODE *pNode = DLL_FIRST (pList);
FAST int count = 0;
while (pNode != NULL)
{
count++;
pNode = DLL_NEXT (pNode);
}
return (count);
}
1.6 遍历节点
节点遍历和返回节点数目函数类似,不再多述。
1.7 删除链表
删除链表和创建链表相对应,主要是释放内存:
STATUS dllDelete
(
DL_LIST *pList /* pointer to list head to be initialized */
)
{
free ((char *) pList); /* free list */
return OK;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
一: 基本数据结构
typedef struct node /* Node of a linked list. */
{
struct node *next; /* Points at the next node in the list */
struct node *previous; /* Points at the previous node in the list */
} NODE;
typedef struct /* Header for a linked list. */
{
NODE node; /* Header list node */
int count; /* Number of nodes in list */
} LIST;
typedef struct dlnode /* Node of a linked list. */
{
struct dlnode *next; /* Points at the next node in the list */
struct dlnode *previous; /* Points at the previous node in the list */
} DL_NODE;
typedef struct /* Header for a linked list. */
{
DL_NODE *head; /* header of list */
DL_NODE *tail; /* tail of list */
} DL_LIST;
二: 网络相关
1. LIST hostList
整个系统的host, hostAdd()产生. hostShow()产看.其中的表项为:
typedef struct
{
NODE node; /*节点链*/
HOSTNAME hostName;/*名称*/
struct in_addr netAddr;/*网络地址*/
} HOSTENTRY;
char targetName [HOSTNAME_LEN]; /* name for this target machine */
2. LIST endList
整个系统已加载的end, muxDevLoad()产生,endFindByName()查看.其中表项为:
typedef struct end_tbl_row
{
NODE node; /* Needed by our list processing library. */
char name[END_NAME_MAX]; /* Name of the devices in row. (ln, etc.) */
LIST units; /* List of devices, i.e. 0, 1, etc.. */
} END_TBL_ROW;
units链表中包含的是真正的END_OBJ.
3. END_TBL_ENTRY endDevTbl[]
整个系统要加载的end,加载后便进入endList.其中表项为:
typedef struct end_tbl_entry
{
int unit; /* This device 's unit # */
END_OBJ* (*endLoadFunc) (char*, void*); /* The Load function. */
char* endLoadString; /* The load string. */
BOOL endLoan; /* Do we loan buffers? */
void* pBSP; /* BSP private */
BOOL processed; /* Has this been processed? */
} END_TBL_ENTRY;
4. _netDpool(_pNetDpool) _netSysPool(_pNetSysPool)
系统网络缓冲区.在netLibInit()-> netLibGeneralInit()-> mbinit()中初始化.
_netDPool(_pNetSysPool)
Only used for data transfer in the network stack.
_netsyspool(_pNetDpool)
Used for network stack system structures such as routes, sockets, protocol control blocks, interface addresses, mulitcast addresses,and multicast routing entries.
5. struct ifnet *ifnet; /* list of all network interfaces */
网络接口链表, 可以使用ifShow()通过遍历ifp-> if_next查看整个表. 由if_attach(ifp)加入一个. ipAttach()内部调用了if_attach().
IP层自己有一个IP_DRV_CTRL ipDrvCtrl[IP_MAX_UNITS], 其中包含了struct ifnet.
最后一个成员是:
struct ifqueue if_snd; /* output queue */
6. UDP和TCP都有in_pcb的链表,指向每个socket的so_pcb.
struct inpcb
{
LIST_ENTRY(inpcb) inp_list; /* list for all PCBs of this proto */
LIST_ENTRY(inpcb) inp_hash; /* hash list */
struct inpcbinfo *inp_pcbinfo;
struct in_addr inp_faddr; /* foreign host table entry */
u_short inp_fport; /* foreign port */
struct in_addr inp_laddr; /* local host table entry */
u_short inp_lport; /* local port */
struct socket *inp_socket; /* back pointer to socket */
caddr_t inp_ppcb; /* pointer to per-protocol pcb */
struct route inp_route; /* placeholder for routing entry */
int inp_flags; /* generic IP/datagram flags */
struct ip inp_ip; /* header prototype; should have more */
struct mbuf *inp_options; /* IP options */
struct ip_moptions *inp_moptions; /* IP multicast options */
};
7. struct protosw inetsw [IP_PROTO_NUM_MAX] Pro tocol switch table,存放各种协议的函数.
Each protocol has a handle initializing one of these structures,
which is used for protocol-protocol and system-protocol communication.
Protocols pass data between themselves as chains of mbufs using the pr_input and pr_output hooks.
pr_input的调用
ipintr()
{
(*inetsw[ip_protox[ip-> ip_p]].pr_input) (m, hlen);
}
struct protosw
{
short pr_type; /* socket type used for */
struct domain *pr_domain; /* domain protocol a member of */
short pr_protocol; /* protocol number */
short pr_flags; /* see below */
void (*pr_input) (); /* input to protocol (from below) */
int (*pr_output) (); /* output to protocol (from above) */
void (*pr_ctlinput) (); /* control input (from below) */
int (*pr_ctloutput) (); /* control output (from above) */
int (*pr_usrreq) (); /* user request: see list below */
void (*pr_init) (); /* initialization hook */
void (*pr_fasttimo) (); /* fast timeout (200ms) */
void (*pr_slowtimo) (); /* slow timeout (500ms) */
void (*pr_drain) (); /* flush any excess space possible */
int (*pr_sysctl) (); /* sysctl for protocol */
};
在ipLibInit(),icmpLibInit(),igmpLibInit(),udpLibInit(),tcpLibInit()等都会有一个protosw.
{
pProtoSwitch
-> pr_type = (0,SOCK_RAW , SOCK_RAW , SOCK_DGRAM, SOCK_STREAM)
-> pr_domain = &inetdomain;
-> pr_protocol = (IPPROTO_IP, IPPROTO_ICMP, IPPROTO_IGMP,IPPROTO_UDP, IPPROTO_TCP)
-> pr_flags = PR_ATOMIC | PR_ADDR;
-> pr_input = (0, icmp_input , igmp_input ,udp_input,tcp_input);
-> pr_output = (ip_output , rip_output, rip_output, 0,0);
-> pr_ctlinput = udp_ctlinput;
-> pr_ctloutput = ip_ctloutput;
-> pr_usrreq = udp_usrreq;
-> pr_init = udp_init;
_protoSwIndex++;
}
8. struct domain *domains; /* list of domain descriptors */
由addDomain (struct domain * pDomain)添加一个新的域.
系统预定义的一个域为:
struct domain inetdomain =
{
AF_INET, "internet ", 0, 0, 0,
inetsw, &inetsw[sizeof(inetsw)/sizeof(inetsw[0])], 0,
rn_inithead, 27, sizeof(struct sockaddr_in)
};
9. RIP ripState;
整个系统的rip状态.
10. struct radix_node_head *rt_tables[]
整个系统的路由表.可以有很多种,如rt_tables[AF_INET].
三: 中断相关
11. INTR_HANDLER intrVecTable[NUM_VEC_MAX] /* Intr vector table */
MPC860 core的外部中断表, 中断定位在0x500处.由intConnect()加入中断,ppc860IntrDeMux()相应中断并分解响应.
四: 设备相关
12. DL_LIST iosDvList
所有已安装的device表, 由iosDevAdd()添加一个表项, iosDelete()删除一个表项.表项为:
typedef struct /* DEV_HDR - device header for all device structures */
{
DL_NODE node; /* device linked list node */
short drvNum; /* driver number for this device,指向drvTable[]相应的位置 */
char * name; /* device name */
} DEV_HDR;
13. DRV_ENTRY drvTable[NUM_DRIVERS] /* max 20 drivers in drvTable */
所有硬件驱动表.由iosDrvInstall()添加表项.其中表项为:
typedef struct /* DRV_ENTRY - entries in driver jump table */
{
FUNCPTR de_create;
FUNCPTR de_delete;
FUNCPTR de_open;
FUNCPTR de_close;
FUNCPTR de_read;
FUNCPTR de_write;
FUNCPTR de_ioctl;
BOOL de_inuse;
} DRV_ENTRY;
14. FD_ENTRY fdTable[NUM_FILES] /* max 50 files open simultaneously */
所有打开的文件描述符表.又fopen()添加一个表项,fclose()删除一个表项.其中表项为:
typedef struct /* FD_ENTRY - entries in file table */
{
DEV_HDR * pDevHdr; /* device header for this file */
int value; /* driver 's id for this file */
char * name; /* actual file name */
BOOL inuse; /* active entry */
} FD_ENTRY;
五: 其他
15.
#define BOOT_LINE_OFFSET 0x4200
#define BOOT_LINE_ADRS ((char *) (LOCAL_MEM_LOCAL_ADRS+BOOT_LINE_OFFSET))
#define DEFAULT_BOOT_LINE "ide=0,0(0,0)host:/vxWorks.dat f=0x8 tn=HC3600 o=cpm "
启动时,如果用户没有输入boot参数,系统便把DEFAULT_BOOT_LINE拷贝到BOOT_LINE_ADRS供 整个系统使用.
- vxworks源码剖析- 数据结构篇一
- vxworks源码剖析- 数据结构篇一(双向链表)_1(转)
- vxworks源码剖析- 数据结构篇一(双向链表)-转
- vxworks源码剖析-对象篇(转)
- Mongoose源码剖析:数据结构篇
- Mongoose源码剖析:数据结构篇
- Mongoose源码剖析:数据结构篇
- Mongoose源码剖析:数据结构篇
- Mongoose源码剖析:数据结构篇
- 菜鸟nginx源码剖析数据结构篇(一)动态数组ngx_array_t
- 菜鸟nginx源码剖析数据结构篇(一) 动态数组ngx_array_t
- 菜鸟nginx源码剖析数据结构篇(一)动态数组ngx_array_t
- stl源码剖析学习笔记(一)重点数据结构概览
- Puppet源码剖析----Type篇(一)
- STL源码剖析(一)
- Chrome源码剖析【一】
- QEMU源码剖析(一)
- Chrome源码剖析【一】
- 手工建库
- container_of宏分析
- 云存储-创业
- android jni调用
- 802.11部分缩略词全名
- vxworks源码剖析- 数据结构篇一
- 深入理解JavaScript中的this关键字
- 条件随机场(Conditional random fields)
- hadoop 2.2 错误总结
- WIN7_ipconfig不是内部或外部命令
- visual studio 选择 .NET Framework版本
- 常用MySQL命令
- 本人修改eclipse的代码提示功能
- Hadoop安装 SSH无密码验证 登录