面向內核空間的 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的主頁。(T002)