实现方式

基础版本的进程间通信比较简单,由三个系统调用完成

linux/arch/x86/entry/syscalls/syscall_64.tbl

新增三个系统调用[作者使用的源码是最新版]

1
2
3
4
# follow three syscall is used for process_communication
442 common zqd_call sys_zqd_call
443 common zqd_server sys_zqd_server
444 common zqd_reply sys_zqd_reply

linux/arch/x86/kernel/sys_x86_64.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
char data[50];
unsigned long rpc_data_len;
long rpc_result;

// struct completion RPC_call_done; initial need
// struct completion RPC_reply_done;

DECLARE_COMPLETION(RPC_reply_done);
DECLARE_COMPLETION(RPC_call_done);

SYSCALL_DEFINE2(zqd_call,void*,rpc_data,size_t,data_len)
{
printk(KERN_INFO "zqd_call...\n");
if(copy_from_user(data,rpc_data,data_len)) // (*to, *from, length) 将client发送的消息copy到data
{
printk(KERN_INFO "zqd_call: failed to copy data to buffer! \n");
return 0;
}

rpc_data_len = data_len;
complete(&RPC_call_done);
wait_for_completion(&RPC_reply_done);
printk(KERN_INFO "rpc_result = ", rpc_result);
return rpc_result;
}

SYSCALL_DEFINE2(zqd_server,void*,buf,size_t*,data_len)
{
printk(KERN_INFO "zqd_server...\n");
wait_for_completion(&RPC_call_done);

if(copy_to_user(buf,data,rpc_data_len)) // (*to, *from, length) 将data内容copy到server的buffer
{
printk(KERN_INFO "zqd_server: failed to copy data to buffer! \n");
return 0;
}
put_user(rpc_data_len,data_len);
return 0;
}

SYSCALL_DEFINE1(zqd_reply,long,result)
{
printk(KERN_INFO "zqd_reply...\n");
rpc_result = result;
complete(&RPC_reply_done);
return 0;
}

测试用例:

client.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <unistd.h>                                                                 
#include <stdio.h>
#include <string.h>
#define __NR_zqd_call 442
typedef unsigned long size_t;

int main(int argc, char const *argv[])
{
char *data = "Hi, top!";
size_t data_len = strlen(data) + 1;
long zqd_call_result = syscall(__NR_zqd_call,data,data_len);
printf("zqd_call_result = %ld\n", zqd_call_result);
printf("\n");
return 0;
}

server.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <unistd.h>                                                               
#include <stdio.h>
#define __NR_zqd_server 443
#define __NR_zqd_reply 444

int main(int argc, char const *argv[])
{
char buffer[20];
long data_len;
long result_server = syscall(__NR_zqd_server,buffer,&data_len);
long result_reply = syscall(__NR_zqd_reply,2048);

printf("data_len = %ld\n", data_len);
printf("data = %s\n", buffer);
printf("server end...\n");
printf("result_server: %ld\n",result_server);
printf("result_reply: %ld\n",result_reply);
return 0;
}

实践小结

服务端正确的打开方式:

启动qemu之后,找到编译后的server.out和client.out

先执行

1
./server.out &		//启动并且后台运行

再执行

1
./client.out

以上代码完成了简化版本的进程间通信,注意编译的时候加上-static参数。如有错误请联系作者更正