现在的位置: 首页 > 综合 > 正文

1.2.5. Function Pointers and Virtual Function Tables (VFTs) 函数指针和虚函数表

2017年08月16日 ⁄ 综合 ⁄ 共 5209字 ⁄ 字号 评论关闭

1.2.5. Function Pointers and Virtual Function Tables (VFTs) 函数指针和虚函数表
Function pointers are a convenient way to write clean C code while getting some of the benefits of the object-oriented languages. In the definition of a data structure type (the object), you include a set of function pointers (the methods). Some or all manipulations of the structure are then done through the embedded functions. C-language function pointers in data structures look like this:
函数指针提供方便的方法去写出干净的有面向对象语言优点的C代码(汗~指正!!!),在数据结构(对象)的定义里,它包含一系列的函数指针(方法)。某些或全部的该数据结构的操作通过这些内嵌的方法完成
struct sock {
    ...
    void    (*sk_state_change)(struct sock *sk);
    void    (*sk_data_ready)(struct sock *sk, int bytes);
    ...

};

A key advantage to using function pointers is that they can be initialized differently depending on various criteria and the role played by the object. Thus, invoking sk_state_change may actually invoke different functions for different sock sockets.
函数指针最显著的优点是依赖于繁多的标准和对象起的不同作用,其能够被不同的初始化。因此不同的sock类sockets调用sk_state_change事实上调用不通的函数。

Function pointers are used extensively in the networking code. The following are only a few examples:
 函数指针在网络编程中广泛应用,下面仅仅是一小部分例子:

When an ingress or egress packet is processed by the routing subsystem, it initializes two routines in the buffer data structure. You will see this in Chapter 35. Refer to Chapter 2 for a complete list of function pointers included in the sk_buff data structure.
当一个进入或发送包被路由子系统处理,它在缓冲数据结构里初始化两个例程。这在35章里有详细描述。第2章里讲述在sk_buff数据结构里的函数指针综述。

When a packet is ready for transmission on the networking hardware, it is handed to the hard_start_xmit function pointer of the net_device data structure. That routine is initialized by the device driver associated with the device.
当一个包准备在网络硬件上传输,他被传递给网络设备数据结构的hard_start_xmit函数指针。那个例程是被连接该设备的设备驱动器初始化。

When an L3 protocol wants to transmit a packet, it invokes one of a set of function pointers. These have been initialized to a set of routines by the address resolution protocol associated with the L3 protocol. Depending on the actual routine to which the function pointer is initialized, a transparent L3-to-L2 address resolution may take place (for example, IPv4 packets go through ARP). When the address resolution is unnecessary, a different routine is used. See Part VI for a detailed discussion on this interface.
当网络层准备传输一个数据包,它会调用一系列的函数指针。这些指针已经被L3层的地址解析协议初始化给很多例程。依赖于函数指针被初始化的实际例程,L3-to-L2传输地址解析可能发生。当不必进行地址解析,一个不同的例程会被应用

We see in the preceding examples how function pointers can be employed as interfaces between kernel components or as generic mechanisms to invoke the right function handler at the right time based on the result of something done by a different subsystem. There are cases where function pointers are also used as a simple way to allow protocols, device drivers, or any other feature to personalize an action.
在前面的例子中我们可以看到函数指针是怎样在不同子系统的运行结果的基础上作为内核各组件接口或是作为普遍标准在正确的时间触发适当的函数调用。还有一种情形 函数指针常常被用来使协议,设备驱动器或其他功能标示自己的动作。

Let's look at an example. When a device driver registers a network device with the kernel, it goes through a series of steps that are needed regardless of the device type. At some point, it invokes a function pointer on the net_device data structure to let the device driver do something extra if needed. The device driver could either initialize that function pointer to a function of its own, or leave the pointer NULL because the default steps performed by the kernel are sufficient.
让我们来看一个例子。 当设备驱动器在内核挂载一个网络设备,他需要经过一系列步骤去屏蔽设备类型,有时在必要的时候,他还会调用该网络设备数据类型的一个函数指针,使得设备驱动器做一些额外的动作。设备驱动器或者用它的一个函数去初始化那个函数指针,或者不会 如果内核执行的默认步骤已经足够。

A check on the value of a function pointer is always necessary before executing it to avoid NULL pointer dereferences, as shown in this snapshot from register_netdevice:
为避免空指针引用,在执行之前检查函数指针是必须的。

    if (dev->init && dev->init(dev) != 0) {
        ...
    }

Function pointers have one main drawback: they make browsing the source code a little harder. While going through a given code path, you may end up focusing on a function pointer call. In such cases, before proceeding down the code path, you need to find out how the function pointer has been initialized. It could depend on different factors:
函数指针有一个主要的缺点:他们让代码可读性变差。当浏览一段给出的代码段,你很可能把焦点停留在一个函数指针的调用上。在这种情形下,在继续浏览之前,你必须弄明白这个函数指针是怎样被初始化的,他依赖于不同的情形:

When the selection of the routine to assign to a function pointer is based on a particular piece of data, such as the protocol handling the data or the device driver a given packet is received from, it is easier to derive the routine. For example, if a given device is managed by the drivers/net/3c59x.c device driver, you can derive the routine to which a given function pointer of the net_device data structure is initialized by reading the device initialization routine provided by the device driver.
当被函数指针选择的例程基于一段特殊数据,像协议提供数据或是一段从设备驱动器得到的数据包,我们能够很简单的确定该例程。比如,给出的硬件被drivers/net/3c59x.c 设备驱动器管理,你能了解到一个网络设备数据结构的函数指针是被那一段例程初始化,通过浏览设备驱动器提供的设备初始化历程。

When the selection of the routine is based instead on more complex logic, such as the state of the resolution of an L3-to-L2 address mapping, the routine used at any time depends on external events that cannot be predicted.
当例程的选择建立在跟复杂的逻辑判定基础上,像解析 L3-to-L2 地址映射,任何时段例程的调用依赖于不可预测的外部事物。

A set of function pointers grouped into a data structure are often referred to as a virtual function table (VFT). When a VFT is used as the interface between two major subsystems, such as the L3 and L4 protocol layers, or when the VFT is simply exported as an interface to a generic kernel component (set of objects), the number of function pointers in it may swell to include many different pointers that accommodate a wide range of protocols or other features. Each feature may end up using only a few of the many functions provided. You will see an example in Part VI. Of course, if this use of a VFT is taken too far, it becomes cumbersome and a major redesign is needed.
很多函数指针的集合被分组入某种数据结构常被称作是虚函数表,当VFT被用来当做两个子系统的接口。像L3和L4协议层之间或当VFT被当成是
一个普通内核模块(对象的集合)接口,里面充斥着大量的函数指针包含范围广泛的不同协议和功能。每个功能最终可能仅仅用了提供的函数中的一小部分。

抱歉!评论已关闭.