主要内容:了解ChChor中的IPC机制。
前提说明:这里的 ipc 是进程间通信( Inter-Process Communication),不是核间通信(Inter-Processor Communication),更不是RPC(Remote Procedure Call)。所以它的主要目的还是把一个进程的数据,传递到目标进程。
ChChore进程间通信的特点
- 通信进程直接切换(有点像rpc,也是启发自LRPC和L4的直接切换技术)
- 同步的通信(client 调用 ipc_call 会阻塞等待 server 处理完然后 return)
- 通过共享内存传输大数据
- 基于Capability的权限控制
- 类似Unix文件描述符的权限机制,Capability表示一个线程/进程对于系统资源的具体权限
用法示例
场景:client需要把自己的一块内存数据传递给server,基于同步的ipc机制
client端
1 | int client() |
上面的第3,4,5,7步是为了演示共享内存数据用的,实际可以不需要。
server端
1 | void ipc_dispatcher(ipc_msg_t * ipc_msg) |
数据结构
代码分析
为了简化分析,先只考虑一个 server 对应一个 client 的场景,因此先忽略多 cliient 的相关内容。
另外,主要分析 内核 相关的 ipc 代码,对用户空间的先不做分析。
注册server
我们要在用户空间的 ipc server thread 执行函数,就得要指定一些信息:比如 callback(具体执行的函数),stack 的起始地址、size;server thread 需要访问共享内存,因此也需要指定 用户空间的 buffer 地址和 size。
这也是 为什么要 这样设置 server_ipc_config 的原因。
1 | u64 sys_register_server(u64 callback, u64 max_client, u64 vm_config_ptr) |
可以看到,注册 ipc server,主要是 创建了 server_ipc_config 并挂到 server thread 上。
注册client
注册一个client,它需要和 server 关联起来;另外一个 client 对应一个connection,因此也需要创建 conn cap 内核对象。另外,client 也有自己的 config 参数,用来保存用户栈空间和共享内存信息。
1 | u32 sys_register_client(u32 server_cap, u64 vm_config_ptr) |
这里面最重要是create_connection
函数,它创建了一个connection内核对象,完成了相关的信息绑定。
1 | static int create_connection(struct thread *source, struct thread *target, |
这个函数有点复杂,主要是完成 conn 的创建,总结一下:
申请一个 conn obj
一个connection需要在server的上下文执行函数,因此需要创建一个 server thread,这是一个 shadow thread
创建 server 线程
获取 server 的 config
根据 config 创建 server 线程的栈
创建 共享内存,完成 内存映射
完成 conn 的配置
client 的 conn_cap 返回给 client,server 的 conn_cap 挂在 conn 数据结构中
这样操作之后,就完成了 server 线程的创建,申请了共享内存,具备了共享数据和在 server thread 执行 callback 的条件。
create_server_thread()
主要是完成真正的 server thread 创建,并配置 server_ipc_config 信息。这里就贴代码了。
ipc_call
client 拿到了 conn_cap,这时候就可以开始进行 ipc_call
了。
1 | u64 sys_ipc_call(u32 conn_cap, ipc_msg_t *ipc_msg) |
主要是两件事情:
- cap拷贝给server
- 转移到server线程执行
1 | int ipc_send_cap(struct ipc_connection *conn, ipc_msg_t *ipc_msg) |
1 | static u64 thread_migrate_to_server(struct ipc_connection *conn, u64 arg) |
ipc_return
1 | static int thread_migrate_to_client(struct ipc_connection *conn, u64 ret_value) |