Fiasco进程间通信


1.概述

Fiasco的进程间通信主要通过do_ipc函数完成,其原型:

void

Thread::do_ipc(L4_msg_tag const &tag,

bool have_send, Thread *partner,

            bool have_receive, Sender *sender,

            L4_timeout_pair t, Syscall_frame *regs,

            L4_fpage::Rights rights)

从定义可以看出do_ipc是属于class Thread。一个线程一般同时具有发和收两种特性,所以在do_ipc函数中可以同时完成收、发两个动作。如参数所示:

:bool have_send(是否有msg需要发送), Thread *partner(接收线程指针),

:bool have_receive(是否需要接收msg, Sender *sender(发送者,NULL为不指定发送者)

当然,也可以只做一个动作,比如只发送时,可以讲have_receive”参数置为false

下面具体分析下这个函数的实现。

2.发送流程

首先分析发送流程(have_send == true),其又分为两种情况:发送和接收线程在同一CPU;发送和接收线程在不同CPU

2.1 同一CPU内发送流程

2.1.1 握手

首先要做的事情是和receiver线程进行握手:handshake_receiver,其原型如下:

inline Thread::Check_sender

Thread::handshake_receiver(Thread *partner, L4_timeout snd_t)

在握手函数里会调用receivercheck_sender函数,来判断发送线程是符合条件的。

inline Thread::Check_sender

Thread::check_sender(Thread *sender, bool timeout)

那么需要符合什么条件呢?我们继续跟代码,看看sender_ok函数。

inline Receiver::Rcv_state

Receiver::sender_ok(const Sender *sender) const

{

  unsigned ipc_state = state() & Thread_ipc_mask;

  // If Thread_send_in_progress is still set, we're still in the send phase

  if (EXPECT_FALSE(ipc_state != Thread_receive_wait))

    return vcpu_async_ipc(sender);

  // Check open wait; test if this sender is really the first in queue

  if (EXPECT_TRUE(!partner()

                  && (_sender_list.empty()

    || sender->is_head_of(&_sender_list))))

    return Rs_ipc_receive;

  // Check closed wait; test if this sender is really who we specified

  if (EXPECT_TRUE(sender == partner()))

    return Rs_ipc_receive;

  return Rs_not_receiving;

}

贴上源码的原因是三条注释已经将函数体表述的非常清楚:

首先,如果发送进程还处于上一个发送过程中,那么调用vcpu_async_ipc函数让其把流程走完;

其次,如果接收进程处于open wait状态(即,未指定特定的发送者<partner()0>),同时发送队列为空或是发送者位于发送队列的head位置,都是满足条件的,返回Rs_ipc_receive

最后,如果接收进程处于closed wait状态(即,指定了发送者),而且发送线程正好是其指定的发送者(sender == partner()),同样是满足要求的,返回Rs_ipc_receive

 

握手成功后,senderpartner的标志设置为Thread_ipc_transfer,保证不会有其他sender向同一个partner发送消息

2.1.2 消息拷贝

第二步就是调用Thread::transfer_msg进行UTCB的拷贝。拷贝完成后,清除partner相关标志后,唤醒partner,整个消息传递过程结束。

2.2 CPU间发送流程

如果senderreceiver处于不同的cpu上,sender无法直接通过调度让receiver运行,只能通过drq的方式来通知receiver运行。其大致思路如下:

1. senderhandshake步骤时, 先发送drq通知receiver。在等待drq响应过程中,sender都是处于Thread_send_wait状态;

2. Receiver响应drq,查询自身的状态和sender是否符合close-wait要求。如果可以的话,自身就进行ipc消息的拷贝(通过remote_ipc_send代码注释,应该ipc消息不包含buffer register时,就可以不持有锁,因此可以在drq上下文中拷贝),并在拷贝完成后更新receiver状态,表示已经收到ipc消息。无论是否拷贝,都需要唤醒sender

3. Sender唤醒后,如果receiver没有拷贝消息,则进行消息拷贝,并通过drq唤醒receiver。如果已经拷贝了消息,直接结束消息发送处理。

3.接收流程

接收流程相对简单,因为它会借助于sender的发送流程来完成自己的接收。

首先,将自身状态设置为Thread_receive_wait,表示自己已经做好接收准备;

然后,在保证自身线程的发送流程已经结束的前提下,找到自己的sender

next = get_next_sender(sender);

这里跟发送流程握手阶段一样,有两种情况:如果sender有值,则表示closed wait,在确保sender在发送列表中,并且阻塞在发送,则返回sender本身,继续接收流程;另外一种情况,senderNULL则表示open wait,则在发送列表中取出第一个,继续接收流程。

接下来,就是设置当前线程为Thread_receive_in_progress状态,调用发送者(前面确定的next对象)的ipc_send_msg方法,通过UTCB拷贝,实现消息传递。

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值