PVFS2源代码分析之输入输出src/io/job/job任务

任务(job)为相关组件和操作提供了一个异步执行的框架,该框架是有状态的(记录于任务描述符job descriptor ),可以记录异步调用执行到哪里等信息,并决定进一步操作;而下层函数调用不记录任务相关的状态(某些具体实现内部可能保存自身的状态),只通过函数参数输入输出任务状态信息。

 

job.c文件中定义的函数很多,因为要涵盖BMI、trove、flow、dev等多个组件的使用,但是不同组件具有相近的模式,我们可以将主要的函数分成如下几类(若干函数用前后缀表示,使用通配符“*”):

  1. 辅以时间管理器(time manager)的异步式
    job_bmi_send
    job_bmi_send_list
    job_bmi_recv
    job_bmi_recv_list
    job_flow
  2. 基于自定义队列的异步式
    job_req_sched_post
    job_req_sched_change_mode
    job_req_sched_post_timer
    job_req_sched_release
    job_trove_bstream_*
    job_trove_keyval_*
    job_trove_dspace_*
    job_trove_fs_*
  3. 同步式
    job_dev_write
    job_dev_write_list
  4. 基于线程管理器(thread manager)的异步式
    job_bmi_unexp
    job_dev_unexp

下面我们分别举例,分析各类函数源代码。同类中的各个函数非常接近,通常只是调用下层接口不同。

  • 辅以时间管理器的异步式

此类函数完成对下层函数的异步调用,将未立即完成的任务加入时间管理器 。我们以函数1为例,分析此类函数的主要行为,同类其他函数完成的主要步骤几乎相同,只是针对不同的下层函数。

 

函数1. job_bmi_send_list

先从参数说起,省略掉的是与具体下层调用相关的参数(在第1行由上层调用传入,在第33、37行转给下层调用),而剩余的参数则基本出现在所有此类函数的定义中。参数中还需说明的是,第4行out_status_p指向一个任务状态,当本函数对应的异步调用当下即完成时,直接填写这个任务状态,告知调用者相关信息;第7行的timeout_sec是超时秒数,基于时间管理器的异步式调用函数均需此参数。除此之外,第2、3、6、8行的参数用于描述任务的相关信息,存入任务描述符(见如下步骤1)。

 

下面说明上述函数的主要行为,可分为四步:

  1. 创建一个任务描述符并保存任务相关信息(第20~29行)
    注释中也提到,这个任务描述符用户任务无法立即完成时加入相关等待队列,其他情况下可能不发挥作用而直接注销掉。
  2. 调用对应的下层函数(第30~38行),并进行错误处理(第39~47行)
    错误处理方式就是撤销任务描述符,并把错误号和相关信息通过任务状态指针out_status_p传出(第42~43行)。
  3. 处理同步的情况
    即任务当即完成,处理方式是撤销任务描述符,把相关信息通过任务状态指针out_status_p传出(第51~53行)
  4. 处理异步的情况
    即需要等待任务执行,处理方式是传出任务描述符ID,并将任务描述符加入时间管理器队列(第63行,参见job_time_mgr_add )。

还要特别说明的是job_context_id类型的参数。我们可以发现,第6行传入的context_id,只是用于在第24行记入任务描述符,并不传入下层调用。可见,该参数是用于本层往上区分任务来源(这也可以说是一种状态信息),对job层往下并不可见;而下层调用(第33、37行)只传入全局值global_bmi_context,即所有job层的BMI调用都视作来自同一个全局上下文,不加区分。

  • 基于自定义队列的异步式

此类函数与上类较为相似,但使用下层组件自备的队列及其相应的对未完成任务的处理方式,函数内不涉及job提供的队列。通过下面函数2可以看到,绝大部分代码和函数1都是对应的,出去调用底层函数不同,几乎唯一的差异就是最后(第59行)没有调用任务时间管理器的job_time_mgr_add函数。

 

函数2. job_trove_keyval_read

  • 同步式

同步式即通过job调用阻塞函数,函数操作完全结束时才继续执行。我们以job_dev_write_list为例,如函数2。

 

函数3. job_dev_write_list

 

注释中也提到,之所以放到job的框架中,也是为日后实现异步版本提供方便(不必更改调用函数)。另外,注意到最终返回值为1,遵从job中异步函数返回值的约定:0表示函数执行成功,1表示任务已立即完成,负数表示错误码。

 

第13~14行调用实际操作函数,这里是阻塞式,等到任务完成函数返回。不论错误处理(第18~20行),还是正常流程(第23~26行),都都是写错误码(error code)及其他相关信息,并通过任务状态指针out_status_p传出;确切说,这里没有在job层保留状态信息,因为任务已经完成。

  • 基于线程管理器的异步式

此类函数与函数1也极为相似,差别也在于最后的操作。当没有意外(BMI中称作unexpected message, dev中称作unexpected receive)到达时,将等待意外任务链入全局变量dev_unexp_queue中(第58行),同时注册处理函数(第61行);与此同时,增加了两个全局计数变量的值——dev_unexp_pending_count(第59行) 和dev_unexp_count(第61行调用的函数中)。然后将后续处理工作较给线程管理器(参见src/io/job/thread-mgr )。

 

函数4. job_dev_unexp

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值