diff --git a/.gitignore b/.gitignore index 9c452a725..2cbccc983 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ *.o *.a skynet +skynet.pid 3rd/lua/lua 3rd/lua/luac cservice diff --git a/Makefile b/Makefile index 35f6626d1..9c84351d4 100644 --- a/Makefile +++ b/Makefile @@ -48,7 +48,7 @@ LUA_CLIB = skynet socketdriver int64 bson mongo md5 netpack \ SKYNET_SRC = skynet_main.c skynet_handle.c skynet_module.c skynet_mq.c \ skynet_server.c skynet_start.c skynet_timer.c skynet_error.c \ skynet_harbor.c skynet_env.c skynet_monitor.c skynet_socket.c socket_server.c \ - malloc_hook.c + malloc_hook.c skynet_daemon.c all : \ $(SKYNET_BUILD_PATH)/skynet \ diff --git a/examples/config b/examples/config index f759d57f1..2f621b830 100644 --- a/examples/config +++ b/examples/config @@ -12,4 +12,4 @@ lualoader = "lualib/loader.lua" -- preload = "./examples/preload.lua" -- run preload.lua before every lua service run snax = root.."examples/?.lua;"..root.."test/?.lua" cpath = root.."cservice/?.so" -daemon = false +daemon = "./skynet.pid" diff --git a/skynet-src/skynet_daemon.c b/skynet-src/skynet_daemon.c new file mode 100644 index 000000000..6a557b764 --- /dev/null +++ b/skynet-src/skynet_daemon.c @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include +#include + +#include "skynet_daemon.h" + +static int +check_pid(const char *pidfile) { + int pid = 0; + FILE *f = fopen(pidfile,"r"); + if (f == NULL) + return 0; + int n = fscanf(f,"%d", &pid); + fclose(f); + + if (n !=1 || pid == 0 || pid == getpid()) { + return 0; + } + + if (kill(pid, 0) && errno == ESRCH) + return 0; + + return pid; +} + +static int +write_pid(const char *pidfile) { + FILE *f; + int pid = 0; + int fd = open(pidfile, O_RDWR|O_CREAT, 0644); + if (fd == -1) { + fprintf(stderr, "Can't create %s.\n", pidfile); + return 0; + } + f = fdopen(fd, "r+"); + if (f == NULL) { + fprintf(stderr, "Can't open %s.\n", pidfile); + return 0; + } + + if (flock(fd, LOCK_EX|LOCK_NB) == -1) { + int n = fscanf(f, "%d", &pid); + fclose(f); + if (n != 1) { + fprintf(stderr, "Can't lock and read pidfile.\n"); + } else { + fprintf(stderr, "Can't lock pidfile, lock is held by pid %d.\n", pid); + } + return 0; + } + + pid = getpid(); + if (!fprintf(f,"%d\n", pid)) { + fprintf(stderr, "Can't write pid.\n"); + close(fd); + return 0; + } + fflush(f); + + if (flock(fd, LOCK_UN) == -1) { + fprintf(stderr, "Can't unlock pidfile %s.\n", pidfile); + close(fd); + return 0; + } + close(fd); + + return pid; +} + +int +daemon_init(const char *pidfile) { + int pid = check_pid(pidfile); + if (pid) { + fprintf(stderr, "Skynet is already running, pid = %d.\n", pid); + return 1; + } + + if (daemon(1,0)) { + fprintf(stderr, "Can't daemonize.\n"); + return 1; + } + + pid = write_pid(pidfile); + if (pid == 0) { + return 1; + } + + return 0; +} + +int +daemon_exit(const char *pidfile) { + return unlink (pidfile); +} diff --git a/skynet-src/skynet_daemon.h b/skynet-src/skynet_daemon.h new file mode 100644 index 000000000..0d99562a1 --- /dev/null +++ b/skynet-src/skynet_daemon.h @@ -0,0 +1,7 @@ +#ifndef skynet_daemon_h +#define skynet_daemon_h + +int daemon_init(const char *pidfile); +int daemon_exit(const char *pidfile); + +#endif diff --git a/skynet-src/skynet_imp.h b/skynet-src/skynet_imp.h index afad0305c..11b12ee10 100644 --- a/skynet-src/skynet_imp.h +++ b/skynet-src/skynet_imp.h @@ -4,7 +4,7 @@ struct skynet_config { int thread; int harbor; - int daemon; + const char * daemon; const char * module_path; const char * bootstrap; }; diff --git a/skynet-src/skynet_main.c b/skynet-src/skynet_main.c index 49f5ed3ce..8596c7786 100644 --- a/skynet-src/skynet_main.c +++ b/skynet-src/skynet_main.c @@ -24,6 +24,7 @@ optint(const char *key, int opt) { return strtol(str, NULL, 10); } +/* static int optboolean(const char *key, int opt) { const char * str = skynet_getenv(key); @@ -33,6 +34,7 @@ optboolean(const char *key, int opt) { } return strcmp(str,"true")==0; } +*/ static const char * optstring(const char *key,const char * opt) { @@ -112,7 +114,7 @@ main(int argc, char *argv[]) { config.module_path = optstring("cpath","./cservice/?.so"); config.harbor = optint("harbor", 1); config.bootstrap = optstring("bootstrap","snlua bootstrap"); - config.daemon = optboolean("daemon", 0); + config.daemon = optstring("daemon", NULL); lua_close(L); diff --git a/skynet-src/skynet_start.c b/skynet-src/skynet_start.c index 91b4f2240..09ab7711f 100644 --- a/skynet-src/skynet_start.c +++ b/skynet-src/skynet_start.c @@ -7,6 +7,7 @@ #include "skynet_timer.h" #include "skynet_monitor.h" #include "skynet_socket.h" +#include "skynet_daemon.h" #include #include @@ -196,8 +197,7 @@ bootstrap(const char * cmdline) { void skynet_start(struct skynet_config * config) { if (config->daemon) { - if (daemon(1,0)) { - fprintf(stderr, "daemon error"); + if (daemon_init(config->daemon)) { exit(1); } } @@ -212,4 +212,7 @@ skynet_start(struct skynet_config * config) { _start(config->thread); skynet_socket_free(); + if (config->daemon) { + daemon_exit(config->daemon); + } }