Administrator
发布于 2022-08-26 / 4 阅读
0
0

ceph-模块初始化中 prefork源码解析

ceph-模块初始化中 prefork源码解析

在 osd启动流程的代码中有一个 global\_init\_prefork() 的 函数,发现在很多 模块启动流程都有 这个函数,这和模块对应的进程有关系,所以对这个函数剖析下

!image-20220901151643117

具体实现函数都在 Preforker 类中 !image-20220901154138047

在先执行是 global\_init\_prefork(g\_ceph\_context) 函数

global_init_prefork(g_ceph_context) ") global\_init\_prefork(g\_ceph\_context)

prefork 的预初始化


int global_init_prefork(CephContext *cct)
{
   // 这里 判断是不是 判断着进程是不是 以守护进程方式启动
  if (g_code_env != CODE_ENVIRONMENT_DAEMON)
    return -1;

  const auto& conf = cct->_conf;
  if (!conf->daemonize) {
        //这里进程的pid 写入文件中
    if (pidfile_write(conf) < 0)
      exit(1);
    //生产了 pid文件后,更改文件权限
    if ((cct->get_init_flags() & CINIT_FLAG_DEFER_DROP_PRIVILEGES) &&
    (cct->get_set_uid() || cct->get_set_gid())) {
      chown_path(conf->pid_file, cct->get_set_uid(), cct->get_set_gid(),
         cct->get_set_uid_string(), cct->get_set_gid_string());
    }

    return -1;
  }
 //这里  告知大家要 pre_fork??????
  cct->notify_pre_fork();
  // stop log thread
  cct->_log->flush();
  cct->_log->stop();
  return 0;
}

pidfile\_write(conf) 函数i就是把进程的 pid 写进 一个文件里,为什么这么做后面再说

!image-20220901162701621

forker.prefork

关键部分,这里主要做的是 fork一个子进程,接下来执行的操作都是由 子进程执行,父进程处于 wait状态,并且这里也对标准输入输出做了些处理

!image-20220901163924371

父进程处于等待状态,再执行 setsid 建立新会话

!image-20220901164030039

global_init_postfork_start(); ;") global\_init\_postfork\_start();

该函数重新再把当前进程的pid重新写入到pid文件

为什么创建一个经常需要 建立一个pid文件? 可这里先从 pid 文件创建开始讲

!image-20220901173051970

在刚才的 pidfile\_write 函数中,有调用了一个 函数 pidfh::open!image-20220901171416846

pidfh::open 中调用了 open,创建 文件 !image-20220901171924980

随后 获取创建文件的信息保存 Preforker 类中 !image-20220901172326150

最后一步比较关键,用 flock 给文件上锁

!image-20220901172606066

这里确保 只有获取锁的进程才能读取文件,没有锁的话直接退出,而且只有一把锁,可以防止进程启动多个副本,只有获得pid文件(固定路径固定文件名)写入权限(F\_WRLCK)的进程才能正常启动并把自身的PID写入该文件中。其它同一个程序的多余进程则自动退出。

假如说我开了两个终端,都同时创建 osd,而且编号都相同,为了确保一个osd对应一个守护进程,跟据程序的设定,必须要读取pid文件才能继续执行,那谁先获得了 pid文件的读写锁,谁就可以继续执行;而且pid文件保存的是 进程的pid,所以可以通过文件来判断进程是否存在


评论