فهرست منبع

hmain.cpp add master-worker

ithewei 6 سال پیش
والد
کامیت
e9eb9b1e55
2فایلهای تغییر یافته به همراه219 افزوده شده و 12 حذف شده
  1. 203 12
      hmain.cpp.tmpl
  2. 16 0
      hsysinfo.h

+ 203 - 12
hmain.cpp.tmpl

@@ -1,4 +1,7 @@
+#include <signal.h> // for signal,kill...
+
 #include "h.h"
+#include "hsysinfo.h"
 
 #include "hmain.h"
 main_ctx_t g_main_ctx;
@@ -17,15 +20,16 @@ int create_pidfile() {
     char pid[16] = {0};
     snprintf(pid, sizeof(pid), "%d\n", g_main_ctx.pid);
     fwrite(pid, 1, strlen(pid), fp);
-    fclose(fp);
+    fclose(fp); atexit(delete_pidfile);
 
-    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() {
@@ -36,6 +40,7 @@ pid_t getpid_from_pidfile() {
     }
     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;
@@ -61,6 +66,11 @@ int main_ctx_init(int argc, char** argv) {
         --e;
     }
     strncpy(g_main_ctx.program_name, e+1, sizeof(g_main_ctx.program_name));
+#ifdef _WIN32
+    if (strcmp(g_main_ctx.program_name+strlen(g_main_ctx.program_name)-4, ".exe") == 0) {
+        *(g_main_ctx.program_name+strlen(g_main_ctx.program_name)-4) = '\0';
+    }
+#endif
     //printf("program_name=%s\n", g_main_ctx.program_name);
 
     // save arg
@@ -139,7 +149,13 @@ int main_ctx_init(int argc, char** argv) {
     g_main_ctx.confile_parser = NULL;
 
     g_main_ctx.oldpid = getpid_from_pidfile();
-    create_pidfile();
+#ifdef __unix__
+    if (kill(g_main_ctx.oldpid, 0) == -1 && errno == ESRCH) {
+        g_main_ctx.oldpid = -1;
+    }
+#else
+
+#endif
 
     return 0;
 }
@@ -173,12 +189,14 @@ void setproctitle(const char* title) {
 #endif
 
 // unix short style
-static char options[] = "hvc:td";
+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\
 ";
 
@@ -240,18 +258,144 @@ next_option:
     return 0;
 }
 
-int main(int argc, char** argv) {
-    main_ctx_init(argc, argv);
+#ifdef __unix__
+// unix use signal
+// we use SIGTERM to quit process
+#define SIGNAL_TERMINATE    SIGTERM
+#include <sys/wait.h>
 
-    parse_cmdline(argc, argv);
+#define MAXNUM_WORKER   1024
+static pid_t s_worker_processes[MAXNUM_WORKER];
 
-/*
-#ifdef __unix__
+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;
+        }
+    }
+}
+#else
+// win32 use Event
+static HANDLE s_hEventTerm = NULL;
+
+void master_process_exit() {
+    CloseHandle(s_hEventTerm);
+    s_hEventTerm = NULL;
+}
+
+void master_process_init() {
+    char eventname[MAX_PATH] = {0};
+    snprintf(eventname, sizeof(eventname), "%s_term_event", g_main_ctx.program_name);
+    s_hEventTerm = CreateEvent(NULL, FALSE, FALSE, eventname);
+    //s_hEventTerm = OpenEvent(EVENT_ALL_ACCESS, FALSE, eventname);
+
+    atexit(master_process_exit);
+}
+
+void master_process_cycle() {
+    while (1) {
+         DWORD ret = WaitForSingleObject(s_hEventTerm, INFINITE);
+         exit(0);
+    }
+}
 #endif
-*/
+
+int main(int argc, char** argv) {
+    main_ctx_init(argc, argv);
+    parse_cmdline(argc, argv);
+    master_process_init();
 
     if (get_arg("h")) {
         print_help();
@@ -274,6 +418,49 @@ int main(int argc, char** argv) {
         exit(0);
     }
 
+    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);
+    }
+
 #ifdef __unix__
     if (get_arg("d")) {
         // nochdir, noclose
@@ -282,14 +469,18 @@ int main(int argc, char** argv) {
             printf("daemon error: %d\n", ret);
             exit(-10);
         }
+        // parent process exit after daemon, so pid changed.
+        g_main_ctx.pid = getpid();
     }
 #endif
 
     hlog_set_file(g_main_ctx.logfile);
     hlog_set_level(LOG_LEVEL_DEBUG);
-    hlogi("version: %s", get_compile_version());
+    hlogi("%s version: %s", g_main_ctx.program_name, get_compile_version());
+    hlogi("%s start/running, pid=%d", g_main_ctx.program_name, g_main_ctx.pid);
 
-    // add code below
+    create_pidfile();
+    master_process_cycle();
 
     return 0;
 }

+ 16 - 0
hsysinfo.h

@@ -0,0 +1,16 @@
+#ifndef H_SYS_INFO_H_
+#define H_SYS_INFO_H_
+
+#include "hplatform.h"
+
+inline int get_ncpu() {
+#ifdef __unix__
+    return sysconf(_SC_NPROCESSORS_CONF);
+#elif defined(_WIN32)
+    SYSTEM_INFO si;
+    GetSystemInfo(&si);
+    return si.dwNumberOfProcessors;
+#endif
+}
+
+#endif // H_SYS_INFO_H_