之前梳理过redis
main函数主体流程
`大体是 initServerConfig() -> loadServerConfig()
-> daemonize() -> initServer() -> aeSetBeforeSleepProc()
->aeMain() -> aeDeleteEventLoop();
initServerConfig()
初始化server的配置
loadServerConfig()
会从配置文件里加载对应的配置
daemonize()
创建守护进程
看一下daemonize的函数组成
1 | void daemonize(void) { |
着重解释下dup2
这个函数
int dup(int oldfd);
复制oldfd所指向的文件描述符,返回系统目前未使用的最小的文件描述符。
新的文件描述符和oldfd指向一个文件,
他们共享读写,枷锁等权限
,当一个文件描述符操作lseek,另一个也会随着偏移
。
但是他们不共享close-on-exec
。
int dup2(int oldfd, int newfd);
复制oldfd到newfd,如果newfd指向的文件打开,那么会关闭该文件。
dup2失败后返回-1,成功则共享文件状态。
接下来看看initServer函数做了些什么 下面是initServer内部的几个步骤
//由于initserver是守护进程,忽略sighup
//sighub在控制终端关闭的时候会发给session首进程
//session首进程退出时,该信号被发送到该session中的前台进程组中的每一个进程signal(SIGHUP, SIG_IGN);
//写管道发现读进程终止时产生sigpipe信号,
//写已终止的SOCK_STREAM套接字同样会产生此信号signal(SIGPIPE, SIG_IGN);
1 | server.pid = getpid(); |
//创建别的模块公用的对象createSharedObjects(); //创建共享对象
adjustOpenFilesLimit(); //改变可打开文件的最大数量
可以看看adjustOpenFilesLimit()
里边做了什么
1 | void adjustOpenFilesLimit(void) { |
回到initServer函数内部
adjustOpenFilesLimit()函数过后是调用
server.el = aeCreateEventLoop(server.maxclients+REDIS_EVENTLOOP_FDSET_INCR);
这个函数是创建基本的时间循环结构。这个api写在Ae.c中,这个文件主要负责创建事件轮询的结构,创建文件读写事件,删除文件读写事件,删除事件轮询结构,派发文件读写功能等,下一节再讲。
然后是创建了一个定时器回调函数
if(aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL) == AE_ERR) { redisPanic("Can't create the serverCron time event."); exit(1); }
接着创建了 TCP的回调函数,主要用于有新的连接到来触发acceptTcpHandler
for (j = 0; j < server.ipfd_count; j++) { if (aeCreateFileEvent(server.el, server.ipfd[j], AE_READABLE, acceptTcpHandler,NULL) == AE_ERR) { redisPanic( "Unrecoverable error creating server.ipfd file event."); } }
//然后添加了udp的回调if (server.sofd > 0 && aeCreateFileEvent(server.el,server.sofd,AE_READABLE, acceptUnixHandler,NULL) == AE_ERR) redisPanic("Unrecoverable error creating server.sofd file event.");
这就是initServer大体的流程