全部博文(668)
分类:
2009-01-01 08:56:46
我们看sk_alloc()函数的代码,其调用了sk_prot_alloc分配一个通用的sock结构体,有可能在高速缓冲中分配也可能在通用缓冲中分配,这个函数的代码并不算长
sys_socketcall()-->
sys_socket()-->sock_create()-->
__sock_create()-->通过pf->create()--> inet_create()-->sk_alloc()-->sk_prot_alloc()
|
如果知道内存管理中的高速缓存的朋友一定很清楚上面的slab的分配方法,kmem_cache_alloc()就是在专用的sock高速缓冲中分配我们要使用的sock结构,而kmalloc()函数则是通用的高速缓冲分配函数,至于这二个函数的具体过程与内存管理密不可分,所以这里如果没有了解或者学习过内核的朋友们,请参阅有关的操作系统理论中的内存管理章节内容,这些内容我们暂且不做说明了。分配成功会,会在sk_alloc()函数中接着对其进行初始化操作,调用sock_lock_init()函数对sock内部同步作用的sk_lock进行初始化
sys_socketcall()-->
sys_socket()-->sock_create()-->
__sock_create()-->通过pf->create()--> inet_create()-->sk_alloc()-->sock_lock_init()
|
调用专用的宏sock_lock_init_class_and_name来完成声明并初始化sk_lock的内容
|
关于细节我们也不追踪了,大多于初始化sk_lock相关。这个sk_lock是一个socket_lock_t结构变量,这是一个专门用于socket的锁结构
|
我们看到其中包括了一个自旋锁slock,还有一个等待队列头wq,而上面的宏sock_lock_init_class_and_name正是对其内容的初始化设置。我们知道在__sock_create()
函数的参数中从
sock_create
传递下来了
current
->
nsproxy
->
net_ns
,这是在进程的数据结构中task_struct中记录网络空间结构的指针,我们将会在后边进一步说明这个结构体struct net.
sock_net_set()
函数将sock结构中的sk_net记录下所属的net空间结构。get_net()是为了增加所属net结构的计数器。
分配了sock结构并做了上述的初始化操作后,再回到inet_create函数中,代码进一步对sock的初始化,注意sk是sock结构,而sock是socket结构。使用inet = inet_sk(sk);使sk赋值给struct inet_sock *inet结构变量,我们在unix的socket中曾经说了关于unix 的socket是unix_sock,而这里用于INET的socket结构inet_sock。然后函数通过sock_init_data(sock, sk);对sk进一步的初始化操作,并让sock和sk挂起钩来。
sys_socketcall()-->
sys_socket()-->sock_create()-->
__sock_create()-->通过pf->create()--> inet_create()-->sock_init_data()
|
sock结构中设置了几个头,它是sk_buff_head结构,我们在前边看sock结构中还没有这个结构体
|
这个结构内部包含了sk_buff结构,它的内容非常大,我们就不看了,sk_buff结构是一个非常重要的数据结构体,无论何种协议都是用该结构体用于封装、载运数据包来使用,每一个数据包都要用一个sk_buff数据结构,所以我们可以看到上面为sk_receive_queue是已经接收到的包,而sk_write_queue则为要发送的的包,上面函数中所有的赋值操作我们暂且不详细分析了,这里是钩子挂钩的过程,当我们遇到具体的操作时,可以回来查看这里的钩子上到底挂了哪个函数。接着,inet_create()还会对inet_sock结构也进行了一些初始化设置,我们还是到“用时理解”其作用,函数中最关键的地方
if (sk->sk_prot->init) { |
这个就是调用了我们上面提到的运输层结构中的钩子函数init.我们看到上面sk_alloc()函数中将是将运输层的钩子结构tcp_prot挂入到sk_prot上了,不明白朋友请回到sk_alloc()函数那里看一下是如何挂入的。这里理所当然进入其init函数这个钩子函数中
struct proto tcp_prot = { |