nginx学习笔记--main模板

main流程

  • 保存命令行
  • 解析命令行
  • 解析配置文件
  • master进程创建多个worker进程,循环处理信号
  • worker进程循环处理事件和定时器

设置进程标题

nginx在unix系统中能设置进程标题,这是一个很酷炫的功能,看看是怎么实现的呢

#ifdef __unix__
/*
 * memory layout
 * argv[0]\0argv[1]\0argv[n]\0env[0]\0env[1]\0env[n]\0
 */
void setproctitle(const char* title) {
    //printf("proctitle=%s\n", title);
    memset(g_main_ctx.os_argv[0], 0, g_main_ctx.arg_len + g_main_ctx.env_len);
    strncpy(g_main_ctx.os_argv[0], title, g_main_ctx.arg_len + g_main_ctx.env_len);
}
#endif

解析命令行

// unix short style
static char options[] = "hvc:ts:d";
static char detail_options[] = "\
-h              : print help\n\
-v              : print version\n\
-c  confile     : set configure file, default etc/${program}.conf\n\
-t              : test configure file and exit\n\
-s  signal      : send signal to process\n\
                  signal=[start, stop, restart, status]\n\
-d              : daemon\n\
";

void print_version() {
    printf("%s version %s\n", g_main_ctx.program_name, get_compile_version());
}

void print_help() {
    printf("Usage: %s [%s]\n", g_main_ctx.program_name, options);
    printf("Options:\n%s\n", detail_options);
}

#define INVALID_OPTION  -1
#define FLAG_OPTION     1
#define PARMA_OPTION    2
int get_option(char opt) {
    char* p = options;
    while (*p && *p != opt) ++p;
    if (*p == '\0')     return INVALID_OPTION;
    if (*(p+1) == ':')  return PARMA_OPTION;
    return FLAG_OPTION;
}

int parse_cmdline(int argc, char** argv) {
    int i = 1;
    while (argv[i]) {
        char* p = argv[i];
        if (*p != '-') {
            printf("Invalid argv[%d]: %s\n", i, argv[i]);
            exit(-10);
        }
        while (*++p) {
            switch (get_option(*p)) {
            case INVALID_OPTION:
                printf("Invalid option: '%c'\n", *p);
                exit(-20);
            case FLAG_OPTION:
                g_main_ctx.arg_kv[std::string(p, 1)] = "true";
                break;
            case PARMA_OPTION:
                if (*(p+1) != '\0') {
                    g_main_ctx.arg_kv[std::string(p, 1)] = p+1;
                    ++i;
                    goto next_option;
                } else if (argv[i+1] != NULL) {
                    g_main_ctx.arg_kv[std::string(p, 1)] = argv[i+1];
                    i += 2;
                    goto next_option;
                } else {
                    printf("Option '%c' requires param\n", *p);
                    exit(-30);
                }
            }
        }
        ++i;
next_option:
        continue;
    }
    return 0;
}

pid文件

int create_pidfile() {
    FILE* fp = fopen(g_main_ctx.pidfile, "w");
    if (fp == NULL) {
        printf("fopen [%s] error: %d\n", g_main_ctx.pidfile, errno);
        return -10;
    }

    char pid[16] = {0};
    snprintf(pid, sizeof(pid), "%d\n", g_main_ctx.pid);
    fwrite(pid, 1, strlen(pid), fp);
    fclose(fp); atexit(delete_pidfile);

    hlogd("create_pidfile [%s] pid=%d", g_main_ctx.pidfile, g_main_ctx.pid);

    return 0;
}

void delete_pidfile() {
    remove(g_main_ctx.pidfile);
    hlogd("delete_pidfile [%s]", g_main_ctx.pidfile);
}

pid_t getpid_from_pidfile() {
    FILE* fp = fopen(g_main_ctx.pidfile, "r");
    if (fp == NULL) {
        //printf("fopen [%s] error: %d\n", g_conf_ctx.pidfile, errno);
        return -1;
    }
    char pid[64];
    int readbytes = fread(pid, 1, sizeof(pid), fp);
    fclose(fp);
    if (readbytes <= 0) {
        printf("fread [%s] bytes=%d\n", g_main_ctx.pidfile, readbytes);
        return -1;
    }
    return atoi(pid);
}

信号控制

在unix系统中使用signal,在windows系统中使用event

    const char* signal = get_arg("s");
    if (signal) {
        if (strcmp(signal, "start") == 0) {
            if (g_main_ctx.oldpid > 0) {
                printf("%s is already running, pid=%d\n", g_main_ctx.program_name, g_main_ctx.oldpid);
                exit(0);
            }
        } else if (strcmp(signal, "stop") == 0) {
            if (g_main_ctx.oldpid > 0) {
#ifdef __unix__
                kill(g_main_ctx.oldpid, SIGNAL_TERMINATE);
#else
                SetEvent(s_hEventTerm);
#endif
                printf("%s stop/waiting\n", g_main_ctx.program_name);
            } else {
                printf("%s is already stopped", g_main_ctx.program_name);
            }
            exit(0);
        } else if (strcmp(signal, "restart") == 0) {
            if (g_main_ctx.oldpid > 0) {
#ifdef __unix__
                kill(g_main_ctx.oldpid, SIGNAL_TERMINATE);
#else
                SetEvent(s_hEventTerm);
#endif
                printf("%s stop/waiting\n", g_main_ctx.program_name);
                msleep(1000);
            }
        } else if (strcmp(signal, "status") == 0) {
            if (g_main_ctx.oldpid > 0) {
                printf("%s start/running, pid=%d\n", g_main_ctx.program_name, g_main_ctx.oldpid);
            } else {
                printf("%s stop/waiting\n", g_main_ctx.program_name);
            }
            exit(0);
        } else {
            printf("Invalid signal: '%s'\n", signal);
            exit(0);
        }
        printf("%s start/running\n", g_main_ctx.program_name);
    }

master-worker模型

#ifdef __unix__
// unix use signal
// we use SIGTERM to quit process
#define SIGNAL_TERMINATE    SIGTERM
#include <sys/wait.h>

#define MAXNUM_WORKER   1024
static pid_t s_worker_processes[MAXNUM_WORKER];

void worker_process_cycle() {
    char proctitle[256] = {0};
    snprintf(proctitle, sizeof(proctitle), "%s: worker process", g_main_ctx.program_name);
    setproctitle(proctitle);

    while(1) {
        msleep(1);
    }
}

int create_worker_process(int worker_processes) {
    for (int i = 0; i < worker_processes; ++i) {
        pid_t pid = fork();
        if (pid < 0) {
            hloge("fork error: %d", errno);
            return errno;
        }
        if (pid == 0) {
            hlogi("worker process start/running, pid=%d", getpid());
            worker_process_cycle();
            exit(0);
        }

        for (int i = 0; i < MAXNUM_WORKER; ++i) {
            if (s_worker_processes[i] <= 0) {
                s_worker_processes[i] = pid;
                break;
            }
        }
    }
    return 0;
}

static int s_signo = 0;
void master_process_signal_handler(int signo) {
    hlogd("pid=%d recv signo=%d", getpid(), signo);
    s_signo = signo;
}

void master_process_init() {
    for (int i = 0; i < MAXNUM_WORKER; ++i) {
        s_worker_processes[i] = -1;
    }
}

void master_process_cycle() {
    char proctitle[256] = {0};
    snprintf(proctitle, sizeof(proctitle), "%s: master process", g_main_ctx.program_name);
    setproctitle(proctitle);

    signal(SIGINT, master_process_signal_handler);
    signal(SIGCHLD, master_process_signal_handler);
    signal(SIGNAL_TERMINATE, master_process_signal_handler);

    sigset_t sigset;
    sigemptyset(&sigset);
    sigaddset(&sigset, SIGINT);
    sigaddset(&sigset, SIGCHLD);
    sigaddset(&sigset, SIGNAL_TERMINATE);
    sigprocmask(SIG_BLOCK, &sigset, NULL);

    create_worker_process(get_ncpu());

    sigemptyset(&sigset);
    while (1) {
        sigsuspend(&sigset);
        switch (s_signo) {
        case SIGINT:
        case SIGNAL_TERMINATE:
            hlogi("killall worker processes");
            for (int i = 0; i < MAXNUM_WORKER; ++i) {
                if (s_worker_processes[i] <= 0) break;
                kill(s_worker_processes[i], SIGKILL);
                s_worker_processes[i] = -1;
            }
            msleep(1000);
            exit(0);
            break;
        case SIGCHLD:
        {
            pid_t pid = 0;
            int status = 0;
            while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
                hlogw("worker process stop/waiting, pid=%d status=%d", pid, status);
                for (int i = 0; i < MAXNUM_WORKER; ++i) {
                    if (s_worker_processes[i] == pid) {
                        s_worker_processes[i] = -1;
                        break;
                    }
                }
                create_worker_process(1);
            }
        }
            break;
        default:
            break;
        }
    }
}
#endif

完整的main模板

https://github.com/ithewei/hw.git下的main.cpp.tmpl文件

repo中提供了Makefile文件
编译步骤如下:

make test
bin/test -d
ps aux | grep test
发布了128 篇原创文章 · 获赞 142 · 访问量 28万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 代码科技 设计师: Amelia_0503

分享到微信朋友圈

×

扫一扫,手机浏览