ceph-模块初始化中 prefork源码解析
在 osd启动流程的代码中有一个 global\_init\_prefork() 的 函数,发现在很多 模块启动流程都有 这个函数,这和模块对应的进程有关系,所以对这个函数剖析下
具体实现函数都在 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 写进 一个文件里,为什么这么做后面再说
forker.prefork
关键部分,这里主要做的是 fork一个子进程,接下来执行的操作都是由 子进程执行,父进程处于 wait状态,并且这里也对标准输入输出做了些处理
父进程处于等待状态,再执行 setsid 建立新会话
global_init_postfork_start(); ;") global\_init\_postfork\_start();
该函数重新再把当前进程的pid重新写入到pid文件
为什么创建一个经常需要 建立一个pid文件? 可这里先从 pid 文件创建开始讲
在刚才的 pidfile\_write 函数中,有调用了一个 函数 pidfh::open!image-20220901171416846
pidfh::open 中调用了 open,创建 文件 !image-20220901171924980
随后 获取创建文件的信息保存 Preforker 类中 !image-20220901172326150
最后一步比较关键,用 flock 给文件上锁
这里确保 只有获取锁的进程才能读取文件,没有锁的话直接退出,而且只有一把锁,可以防止进程启动多个副本,只有获得pid文件(固定路径固定文件名)写入权限(F\_WRLCK)的进程才能正常启动并把自身的PID写入该文件中。其它同一个程序的多余进程则自动退出。
假如说我开了两个终端,都同时创建 osd,而且编号都相同,为了确保一个osd对应一个守护进程,跟据程序的设定,必须要读取pid文件才能继续执行,那谁先获得了 pid文件的读写锁,谁就可以继续执行;而且pid文件保存的是 进程的pid,所以可以通过文件来判断进程是否存在