面向内核空间的 API
这些API接口向位于内核空间的用户提供了管理relay通道、数据写入等功能。下面介绍其中主要的部分,完整的API接口列表请参见这里。
relay_open() - 创建一个relay通道,包括创建每个CPU对应的relay缓冲区。
relay_close() - 关闭一个relay通道,包括释放所有的relay缓冲区,在此之前会调用relay_switch()来处理这些relay缓冲区以保证已读取但是未满的数据不会丢失
relay_write() - 将数据写入到当前CPU对应的relay缓冲区内。由于它使用了local_irqsave()保护,因此也可以在中断上下文中使用。
relay_reserve() - 在relay通道中保留一块连续的区域来留给未来的写入操作。这通常用于那些希望直接写入到relay缓冲区的用户。考虑到性能或者其它因素,这些用户不希望先把数据写到一个临时缓冲区中,然后再通过relay_write()进行写入。
Relay的例子
我们用一个最简单的例子来介绍怎么使用Relay。这个例子由两部分组成:一部分是位于内核空间将数据写入relay文件的程序,使用时需要作为一个内核模块被加载;另一部分是位于用户空间从relay文件中读取数据的程序,使用时作为普通用户态程序运行。
内核空间的程序主要操作是:
加载模块时,打开一个relay通道,并且往打开的relay通道中写入消息;
卸载模块时,关闭relay通道。
程序内容:
/*
* hello-mod.c
* a kernel-space client example of relayfs filesystem
*/
#include
#include
static struct rchan *hello_rchan;
int init_module(void)
{
const char *msg="Hello world\n";
hello_rchan = relay_open("cpu", NULL, 8192, 2, NULL);
if(!hello_rchan){
printk("relay_open() failed.\n");
return -ENOMEM;
}
relay_write(hello_rchan, msg, strlen(msg));
return 0;
}
void cleanup_module(void)
{
if(hello_rchan) {
relay_close(hello_rchan);
hello_rchan = NULL;
}
return;
}
MODULE_LICENSE ("GPL");
MODULE_DESCRIPTION ("Simple example of Relay");
用户空间的函数主要操作是:
如果relayfs文件系统还没有被mount,则将其mount到目录/mnt/relay上;
遍历每一个CPU对应的缓冲文件
打开文件
读取所有文件内容
关闭文件
最后,umount掉relay文件系统。
程序内容:
/*
* audience.c
* a user-space client example of relayfs filesystem
*/
#include
#include
#include
#include
#include
#include
#include
#define MAX_BUFLEN 256
const char filename_base[]="/mnt/relay/cpu";
// implement your own get_cputotal() before compilation
static int get_cputotal(void);
int main(void)
{
char filename[128]={0};
char buf[MAX_BUFLEN];
int fd, c, i, bytesread, cputotal = 0;
if(mount("relayfs", "/mnt/relay", "relayfs", 0, NULL)
&& (errno != EBUSY)) {
printf("mount() failed: %s\n", strerror(errno));
return 1;
}
cputotal = get_cputotal();
if(cputotal <= 0) {
printf("invalid cputotal value: %d\n", cputotal);
return 1;
}
for(i=0; i // open per-cpu file
sprintf(filename, "%s%d", filename_base, i);
fd = open(filename, O_RDONLY);
if (fd < 0) {
printf("fopen() failed: %s\n", strerror(errno));
return 1;
}
// read per-cpu file
bytesread = read(fd, buf, MAX_BUFLEN);
while(bytesread > 0) {
buf[bytesread] = '\0';
puts(buf);
bytesread = read(fd, buf, MAX_BUFLEN);
};
// close per-cpu file
if(fd > 0) {
close(fd);
fd = 0;
}
}
if(umount("/mnt/relay") && (errno != EINVAL)) {
printf("umount() failed: %s\n", strerror(errno));
return 1;
}
return 0;
}
上面这个例子给出了使用relay的一个最简单的情形,并没有实际用处,但是形象描述了从用户空间和内核空间两个方面使用relay的基本流程。实际应用中对relay的使用当然要比这复杂得多。更多的例子请参见relay的主页。