Solaris 动态跟踪指南

转换器声明

转换器是由接口供应商提供的 D 赋值语句的集合,可用于将输入表达式转换为结构类型的对象。为了解转换器的必要性和用法,我们将以 stdio.h 中定义的 ANSI-C 标准库例程为例。这些例程作用于名为 FILE 的数据结构,该数据结构的实现产物是从 C 程序编制器中抽象出来的。创建数据结构抽象的标准方法是:在单独的专用头文件中保留相应的结构定义的同时,在公共头文件中仅提供数据结构的转发声明。

如果要编写 C 程序并且希望知道对应于 FILE 结构的文件描述符,则可以使用 fileno(3C) 函数获取该描述符,而不是直接取消对 FILE 结构成员的引用。Solaris 头文件通过将 FILE 定义为不透明的转发声明标记来强制实施此规则,这样包括 <stdio.h> 的 C 程序将不能直接取消对 FILE 结构成员的引用。在 libc.so.1 库中,可以假设按照以下形式使用 C 语言实现 fileno()

int
fileno(FILE *fp)
{
	struct file_impl *ip = (struct file_impl *)fp;

	return (ip->fd);
}

假设 fileno() 接受 FILE 指针作为参数,并将其强制转换为指向相应内部 libc 结构 struct file_impl 的指针,然后返回该实现结构的 fd 成员的值。为什么 Solaris 按照此形式实现接口?通过在客户机程序中对当前 libc 实现的详细信息进行抽象,Sun 可以保持对强大二进制兼容性的承诺,同时继续发展和更改 libc 的内部实现详细信息。在示例中,fd 成员可以更改 struct file_impl(甚至修补程序)中的大小和位置,调用 fileno(3C) 的现有二进制文件不会受此更改的影响,因为它们不依赖于这些人为因素。

不过,观察软件(如 DTrace)必须能够全面监测实现的内部以提供有用的结果,但它不具有调用在 Solaris 库或内核中定义的任意 C 函数的能力。可以在 D 程序中声明 struct file_impl 的副本以便检测 stdio.h 中声明的例程,但您的 D 程序将依赖于库的“专用”实现产物,该库可能在将来的微发行版或次发行版甚至修补程序中中断。理论上,我们要提供绑定到库的实现并进行相应更新的结构,以供 D 程序使用,并且能提供与更好的稳定性关联的其他抽象层。

使用以下形式的声明创建新的转换器:

translator output-type < input-type input-identifier > {
	member-name = expression ;
	member-name = expression ;
	...
};	

output-type 指定一个结构,这将是转换的结果类型。input-type 指定输入表达式的类型,并括在尖括号 < > 中,后跟可在转换器表达式中用作输入表达式的别名的 input-identifier。转换器的主体括在花括号 { } 中,以分号 (;) 结尾,由 member-name 和与转换表达式对应的标识符的列表组成。每个成员声明必须命名一个唯一的 output-type 成员,且必须根据 D 赋值 (=) 运算符的规则指定与成员类型兼容的类型表达式。

例如,可以根据一些可用的 libc 接口,定义一个有关 stdio 文件的稳定信息结构:

struct file_info {
	int file_fd;   /* file descriptor from fileno(3C) */
	int file_eof;  /* eof flag from feof(3C) */
};

然后可以在 D 中声明从 FILEfile_info 的假设 D 转换器,如下所示:

translator struct file_info < FILE *F > {
	file_fd = ((struct file_impl *)F)->fd;
	file_eof = ((struct file_impl *)F)->eof;
};

在假设的转换器中,输入表达式为 FILE * 类型,且指定了 input-identifier F。然后可以在转换器成员表达式中将标识符 F 用作 FILE *(仅在转换器声明的主体中可见)类型的变量。要确定 file_fd 输出成员的值,转换器将按照上面所示的 fileno(3C) 假设实现的类似方式,执行强制类型转换和取消引用。还将执行类似的转换以获取 EOF 指示符的值。

Sun 提供了一组可与 Solaris 接口一起使用的转换器(可在 D 程序中调用这些转换器),并承诺,当相应接口的实现发生变化时,将根据先前定义的接口稳定性规则维护这些转换器。在本章的后面部分中,我们将在学习如何通过 D 调用转换器之后,来学习这些转换器。对于想要提供自定义的转换器以供 D 程序员观察其软件包的状态的应用程序和库开发者,转换器工具本身也可供他们使用。