#At file:///home/msvensson/mysql/6.4-bug43559-new/ based on revid:msvensson@stripped
2932 Magnus Svensson 2009-03-13
Bug#43559 ndb_mgmd in daemon mode does not work
- reorganize the my_daemon interface so that it better suites
it's dual task of making the application run as a service on windows
and as a daemon on other platforms.
- Take full advantage of the NTService class.
- put the subfunction in ndb_mgmd's main back together, they don't need to be split
up anymore.
- add "mini" main to ndb_mgmd that calls my_daemon_init and does the magic
run as service tricks
modified:
storage/ndb/include/portlib/my_daemon.h
storage/ndb/src/common/portlib/my_daemon.cc
storage/ndb/src/mgmsrv/MgmtSrvr.hpp
storage/ndb/src/mgmsrv/main.cpp
per-file messages:
storage/ndb/include/portlib/my_daemon.h
reorganize my_daemon interface
storage/ndb/src/common/portlib/my_daemon.cc
- Reorganize my_daemon interface
- Take full advantage of the NTService class
- Support --install[=<service_name>], --remove[=<service_name>]
and --service[=<service_name>] behind the scenes for an application
that uses the my_dameon library
- Fix the cause of bug, calling setsid _after_ fork
storage/ndb/src/mgmsrv/MgmtSrvr.hpp
No need to add extra options to application anymore
storage/ndb/src/mgmsrv/main.cpp
- Remove the split of mgmd's main into subfunctions, not needed anymore.
- Create "mini" main that call's my_daemon_init which handles the magic
of becoming a service on windows.
=== modified file 'storage/ndb/include/portlib/my_daemon.h'
--- a/storage/ndb/include/portlib/my_daemon.h 2009-03-11 12:19:17 +0000
+++ b/storage/ndb/include/portlib/my_daemon.h 2009-03-13 09:03:33 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2008 Sun Microsystems
+/* Copyright (C) 2008-2009 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,100 +18,50 @@
C_MODE_START
-/*
- all functions return 0 for success so the retval can be returned from main()
-
- to run the daemon, you must provide a struct MY_DAEMON * to my_daemon_run().
- the two functions in that struct are start() and stop()
-
- int start(void*)
- . this function should do the main work of the daemon
- . on windows, it is run in a new thread.
- -- the parameter to start will always be 0.
- -- the return value of start is ignored
-
- int stop()
- . when called, this function must terminate the start() function
- . usually, start() runs an event loop and setting a global variable
- to 0 breaks the loop. stop() should set this variable to 0.
- -- the return value is ignored
-*/
-
-typedef int (*daemon_start_t)(void *);
-typedef int (*daemon_onstop_t)();
-struct MY_DAEMON {
- daemon_start_t start;
- daemon_onstop_t stop;
-};
-
-int my_daemon_run(char *name, struct MY_DAEMON*d);
+typedef int (*my_daemon_run_t)(int, char**);
+typedef void (*my_daemon_stop_t)(void);
/*
- if any of the functions in my_daemon return non-zero (failure)
- then my_daemon_error contains the error message
-*/
+ Used from "mini" main to run an application as a
+ service on windows, where the "run" function will be run
+ as a service if first arg is --service=<service_name>.
-extern char my_daemon_error[];
+ Defaults to "normal" behaviour which is to call "run" directly
+ with argc/argv
-int maybe_install_or_remove_service(int argc_,
- char**argv_,
- char*opts_remove,
- char*opts_install,
- char*default_name);
+*/
+int my_daemon_init(int argc, char** argv,
+ my_daemon_run_t run, my_daemon_stop_t stop,
+ const char* name, const char* display_name);
/*
- these macros are provided for convenience. including these macros
- in your main source file give you standard options for services
-*/
-#define NONE
-#ifdef _WIN32
-#define MY_DAEMON_VARS_PASTE(prefix) \
- uchar *prefix##remove,*prefix##install,*prefix##service
-#define MY_DAEMON_VARS(prefix) uchar *prefix remove,* install,*prefix service
-#define MY_DAEMON_VARS0 MY_DAEMON_VARS(NONE)
-#define MY_DAEMON_LONG_OPTS(prefix) \
- {"install", 'i', "Install this program as a service. (must be first argument)", \
- &prefix install, &prefix install, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, \
- {"remove", 'r', "Remove this program as a service. (must be first argument)", \
- &prefix remove, &prefix remove, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, \
- {"service", 's', "Internal use only (for windows service)", \
- &prefix service, &prefix service, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
-
-#else
-#define MY_DAEMON_VARS_PASTE(prefix)
-#define MY_DAEMON_VARS(prefix)
-#define MY_DAEMON_VARS0
-#define MY_DAEMON_LONG_OPTS(prefix)
-#define MY_DAEMON_LONG_OPTS_PASTE(prefix)
-#endif
+ To be called at the point where an application needs to daemonize
+ itself.
+ The daemonizing will on most platforms do a fork itself as a daemon.
+ I.e fork, setsid, create pidfile, and redirect all output to logfile.
-/*
- my_daemon_prefiles() checks that pidname and logname can be created
- and that pidname can be locked.
- a non-zero return usually means that the process abort -- can't create
- necessary files.
+ On windows, only create pidfile and redirect.
*/
-
-int my_daemon_prefiles(const char *pidname, const char *logname);
+int my_daemonize(const char* pidfile_name, const char *logfile_name);
/*
- my_daemon_files() opens the files passed in prefiles() and redirects
- stdout/stderr to the logfile.
- my_dlog points is the logfile after daemon_files()
-*/
+ To be called when application should exit.
-int my_daemon_files();
+ Performs an ordered shutdown of service if running as a serevice.
+ */
+void my_daemon_exit(int status);
/*
- a helper function to turn a --install command line to a
- --service command line for internal use with MY_DAEMON_LONG_OPTS
+ if any of the functions in my_daemon return non-zero (failure)
+ then my_daemon_error contains the error message
*/
-char *my_daemon_make_svc_cmd(int n, char **v, char *default_name);
+extern char my_daemon_error[];
C_MODE_END
+
#endif //MY_DAEMON_H
=== modified file 'storage/ndb/src/common/portlib/my_daemon.cc'
--- a/storage/ndb/src/common/portlib/my_daemon.cc 2009-03-11 12:23:00 +0000
+++ b/storage/ndb/src/common/portlib/my_daemon.cc 2009-03-13 09:03:33 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2008 Sun Microsystems
+/* Copyright (C) 2008-2009 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -22,19 +22,9 @@
#include <m_string.h>
#include <my_daemon.h>
-#ifdef _WIN32
-#include <nt_servc.h>
-NTService g_ntsvc;
-HANDLE g_shutdown_evt;
-#endif
-
-static FILE *my_dlog;
-static char *daemon_name;
-static long daemonpid;
-static int pidfd, logfd;
-
-static const char *pidfile, *logfile;
+#include <BaseString.hpp>
+static FILE *dlog_file;
static int ERR1(const char* fmt, ...)
ATTRIBUTE_FORMAT(printf, 1, 2);
@@ -49,277 +39,335 @@ static int ERR1(const char* fmt, ...)
return 1;
}
-struct MY_DAEMON g_daemon;
#ifdef _WIN32
-static DWORD WINAPI main_function(LPVOID x)
-{
- g_ntsvc.SetRunning();
- g_daemon.start(0);
- return 0;
-}
+#include <nt_servc.h>
+static NTService g_ntsvc;
-static int init()
-{
- return !g_ntsvc.Init(daemon_name,main_function);
-}
+static int g_argc;
+static char** g_argv;
-static int stopper(void*)
-{
- WaitForSingleObject(g_shutdown_evt,INFINITE);
- return g_daemon.stop();
-}
-#endif
+static HANDLE g_shutdown_event;
+static my_daemon_stop_t g_stop_func;
+static my_daemon_run_t g_run_func;
-int my_daemon_run(char *name,struct MY_DAEMON*d)
-{
- daemon_name= name;
- memcpy(&g_daemon,d,sizeof(g_daemon));
-#ifdef _WIN32
- g_shutdown_evt=CreateEvent(0, 0, 0, 0);
- g_ntsvc.SetShutdownEvent(g_shutdown_evt);
- uintptr_t stop_thread= _beginthread((THREAD_FC)stopper,0,0);
- if(!stop_thread)
- return ERR1("couldn't start stopper thread");
- if(init())
- return ERR1("init failed");
-#else /* Fork */
- pid_t n = fork();
- if(n==-1)
- return ERR1("fork failed, errno: %d, error: %s", errno, strerror(errno));
- /* Exit if we are the parent */
- if (n != 0)
- exit(0);
- g_daemon.start(0);
-#endif
- return 0;
-}
-#ifdef _WIN32
-char *my_daemon_makecmdv(int c, const char **v)
+static void stopper_thread(void*)
{
- char exe[_MAX_PATH + 3], *retval, *strpos;
- int i= 0, n= 0;
+ // Wait forever until the shutdown event is signaled
+ WaitForSingleObject(g_shutdown_event, INFINITE);
- GetModuleFileName(NULL, exe, sizeof(exe));
- n= strlen(exe);
- for (i= 0; i < c; i++)
- n += strlen(v[i]) + 8;
- strpos= retval= (char*)my_malloc(n, MY_FAE);
- strpos += my_snprintf(strpos, n, "\"%s\"", exe);
- for (i= 0; i < c; i++)
- strpos += my_snprintf(strpos, n, " \"%s\"", v[i]);
- return retval;
-}
-
-static int startswith(char*s,char**set)
-{
- char**item=set;
- for(;*item;item++)
- if(!strncmp(*item,s,strlen(*item)))
- return 1;
- return 0;
-}
-
-char *my_daemon_make_svc_cmd(int n, char **v, char *name)
-{
- char*swi[]= {"--install","-i",0},
- *swirs[]= {"--remove","-r","--install","-i","--service","-s",0};
- if(!startswith(v[0],swi))
- return ERR1("The install option (-i) must be the first argument"),0;
- int i= 0;
- for(i=1;i<n;i++)
- if(startswith(v[i],swirs))
- return ERR1("The install option (-i) must be the only -i or -r"
- " on command line"),0;
- size_t opt_size= strlen(name)+16;
- char*svcopt=(char*)my_malloc(opt_size, MY_FAE);
- my_snprintf(svcopt,opt_size-1,"--service=%s",name);
-
- size_t size=sizeof(char*)*(n+2);
- char**v1= (char**)my_malloc(size, MY_FAE);
- memset(v1,0,size);
- i=0;
- v1[i++]= svcopt;
-
- int j= 1;
- for(;j<n&&v[j][0]!='-';j++); // skip through to first option
- for(;j<n;j++)
- v1[i++]= v[j];
- return my_daemon_makecmdv(i, (const char**)v1);
+ // Call the installed stop callback function
+ g_stop_func();
}
/*
- my_daemon_install() adds a service called [name] which will
- be called using the command line [cmd]
- to start a service after installing it, you can use the command line
- > net start [name]
+ This function is called like:
+ <service dipatcher thread>
+ - NTService::ServiceMain
+ - NTService::StartService
+ <new service thread>
+ -service_main
+ and runs the "application" through
+ the installed callback function "g_run_func"
*/
-static int my_daemon_install(const char *name, const char *cmd)
+static int service_main(NTService* service)
{
- SC_HANDLE svc= 0, scm= 0;
+ /* Inform SCM that service is running and can be stopped */
+ service->SetRunning();
- if(!g_ntsvc.SeekStatus(name, 1))
- return ERR1("SeekStatus on %s failed", name);
- if(!(scm= OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE)))
- return ERR1("Failed to install the service: "
- "Could not open Service Control Manager.");
- if(!(svc= CreateService(scm, name, name,
- SERVICE_ALL_ACCESS,
- SERVICE_WIN32_OWN_PROCESS,
- (1 ? SERVICE_AUTO_START :
- SERVICE_DEMAND_START), SERVICE_ERROR_NORMAL,
- cmd, 0, 0, 0, 0, 0)))
- return CloseServiceHandle(scm),
- ERR1("Failed to install the service: "
- "Couldn't create service)");
- printf("Service successfully installed.");
- CloseServiceHandle(svc);
- CloseServiceHandle(scm);
- return 0;
+ /* Run the application with with argc/argv */
+ return g_run_func(g_argc, g_argv);
}
/*
- my_daemon_remove() deletes any service called [name]
+ Check if "arg" contains "option", return the
+ options argument in opt_arg(i.e everything after =)
*/
-static int my_daemon_remove(const char *name)
+static bool
+is_option(const char* arg, const char* option, const char** opt_arg)
{
- return !g_ntsvc.Remove((LPCSTR)name);
+ size_t option_len = strlen(option);
+ if (strncmp(arg, option, option_len))
+ return false; // No hit
+
+ // Step forward to the end of --<option>
+ arg+= option_len;
+ if (*arg == '=')
+ {
+ /* Assign opt_arg pointer to first char after = */
+ *opt_arg= arg + 1;
+ }
+ return true;
}
-//returns -1: no install/remove, 0: success, +ve error
-int maybe_install_or_remove_service(int argc_,char**argv_,char*opts_remove,char*opts_install,char*default_name)
+static int
+install_or_remove_service(int argc, char** argv,
+ const char* name, const char* display_name)
{
- if(argc_<2)
- return -1;
- char*svc=default_name,
- *r[]={"-r","--remove",0},
- *i[]={"-i","--install",0};
- if(opts_remove||startswith(argv_[1],r)) {
- if(opts_remove)
- svc=(char*)opts_remove;
- printf("Removing service \"%s\"",svc);
- return my_daemon_remove(svc);
+ if (argc < 2)
+ return 0; // Nothing to do
+
+ /* --remove as first argument on command line */
+ const char* remove_name = NULL;
+ if (is_option(argv[1], "--remove", &remove_name))
+ {
+ if (remove_name)
+ {
+ /* Use the part after = as service name _and_ display name */
+ name = display_name = remove_name;
+ }
+ printf("Removing service '%s'\n", display_name);
+ /* Remove service. Ignore return value, error is printed to stdout */
+ (void)g_ntsvc.Remove(name);
+ return 1;
}
- if(opts_install||startswith(argv_[1],i)) {
- char *svc_cmd;
- if(opts_install)
- svc=(char*)opts_install;
- svc_cmd= my_daemon_make_svc_cmd(argc_-1, argv_+1, svc);
- if(!svc_cmd) {
- fprintf(stderr, my_daemon_error);
- return 1;
+
+ const char* install_name = NULL;
+ if (is_option(argv[1], "--install", &install_name))
+ {
+ if (install_name)
+ {
+ /* Use the part after = as service name _and_ display name */
+ name = display_name = install_name;
}
- printf("Installing service \"%s\"",svc);
- printf("as \"%s\"",svc_cmd);
- return my_daemon_install(svc, svc_cmd);
+
+ BaseString cmd;
+
+ /* Full path to this binary */
+ char exe[MAX_PATH];
+ GetModuleFileName(NULL, exe, sizeof(exe));
+ cmd.assfmt("\"%s\"", exe);
+
+ /* The option that tells which service is starting */
+ cmd.appfmt(" \"--service=%s\"", name);
+
+ /* All the args after --install(which must be first) */
+ for (int i = 2; i < argc; i++)
+ cmd.appfmt(" \"%s\"", argv[i]);
+
+ printf("Installing service '%s' as '%s'\n", display_name, cmd.c_str());
+
+ /* Install service. Ignore return value, error is printed to stdout */
+ (void)g_ntsvc.Install(1, name, display_name, cmd.c_str());
+ return 1;
}
- return -1;
+ return 0;
}
+#endif
+
+int my_daemon_init(int argc, char** argv,
+ my_daemon_run_t run, my_daemon_stop_t stop,
+ const char* name, const char* display_name)
+{
+#ifdef _WIN32
+ // Check for --install or --remove options
+ if (install_or_remove_service(argc, argv, name, display_name))
+ return 1;
+
+ // Check if first arg is --service -> run as service
+ const char* service_name = NULL;
+ if (argc > 1 &&
+ is_option(argv[1], "--service", &service_name) &&
+ service_name)
+ {
+ // Create the shutdown event that will be signaled
+ // by g_ntsvc if the service is to be stopped
+ g_shutdown_event = CreateEvent(0, 0, 0, 0);
+
+ // Install the shutdown event in g_ntsvc
+ g_ntsvc.SetShutdownEvent(g_shutdown_event);
+
+ // Save the stop function so it can be called
+ // by 'stopper_thread'
+ g_stop_func = stop;
+
+ // Create a thread whose only purpose is to wait for
+ // the shutdown event to be signaled and then call the 'stop'
+ // function
+ uintptr_t stop_thread = _beginthread(stopper_thread,0,0);
+ if(!stop_thread)
+ return ERR1("couldn't start stopper thread");
+
+ // Save the run function so it can be called
+ // by 'service_main'
+ g_run_func = run;
+
+ // Build argv without --service
+ BaseString cmd;
+ for (int i = 2; i < argc; i++)
+ cmd.appfmt(" %s", argv[i]);
+ g_argv = BaseString::argify(argv[0], cmd.c_str());
+ g_argc = argc - 1;
+
+ // Start the service thread and let it run 'service_main'
+ // This call will not return until the service thread returns
+ return g_ntsvc.Init(service_name, service_main);
+ }
#endif
-int daemon_closefiles()
+ // Default behaviour, run the "run" function which
+ // should be the "applications" real main
+ return run(argc, argv);
+
+}
+
+
+#ifdef _WIN32
+
+#define F_TLOCK _LK_NBLCK
+#define F_ULOCK _LK_UNLCK
+#define F_LOCK _LK_LOCK
+
+static inline int lockf(int fd, int cmd, off_t len)
{
- close(pidfd);
- fclose(my_dlog);
- return 0;
+ return _locking(fd, cmd, len);
}
-int my_daemon_prefiles(const char *pidfil, const char *logfil)
+static inline int ftruncate(int fd, off_t length)
{
- int n;
- char buf[64];
+ return _chsize(fd, length);
+}
+#endif
+
- my_dlog= 0;
- pidfile= pidfil;
- logfile= logfil;
- pidfd= logfd= -1;
- /* open log file before becoming daemon */
- if (logfile != NULL)
+static int
+check_files(const char *pidfile_name,
+ const char *logfile_name,
+ int *pidfd_ret, int *logfd_ret)
+{
+ /* Open log file if any */
+ if (logfile_name)
{
- logfd= open(logfile, O_CREAT | O_WRONLY | O_APPEND, 0644);
+ int logfd = open(logfile_name, O_CREAT | O_WRONLY | O_APPEND, 0644);
if(logfd == -1)
return ERR1("Failed to open logfile '%s' for write, errno: %d",
- logfile, errno);
- my_dlog= fdopen(logfd, "a");
+ logfile_name, errno);
+ dlog_file = fdopen(logfd, "a");
+ *logfd_ret = logfd;
}
+
/* Check that we have write access to lock file */
- assert(pidfile != NULL);
- pidfd= open(pidfile, O_CREAT | O_RDWR, 0644);
- if(pidfd == -1)
+ if (!pidfile_name)
+ return ERR1("Missing pid file name");
+ int pidfd= open(pidfile_name, O_CREAT | O_RDWR, 0644);
+ if (pidfd == -1)
return ERR1("Failed to open pidfile '%s' for write, errno: %d",
- pidfile, errno);
+ pidfile_name, errno);
+
/* Read any old pid from lock file */
- n= read(pidfd, buf, sizeof(buf));
- if(n < 0)
- return ERR1("Failed to read from pidfile '%s', errno: %d", pidfile, errno);
- buf[n]= 0;
- daemonpid= atol(buf);
+ char buf[32];
+ int bytes_read = read(pidfd, buf, sizeof(buf));
+ if(bytes_read < 0)
+ return ERR1("Failed to read from pidfile '%s', errno: %d",
+ pidfile_name, errno);
+ buf[bytes_read]= 0;
+ long currpid= atol(buf);
if(lseek(pidfd, 0, SEEK_SET) == -1)
- return ERR1("Failed to lseek pidfile '%s', errno: %d", pidfile, errno);
-#ifdef __WIN__ //TODO: add my_lockf.c with these definitions
-#define lockf _locking
-#define F_TLOCK _LK_NBLCK
-#define F_ULOCK _LK_UNLCK
-#define F_LOCK _LK_LOCK
-#endif
-#ifdef F_TLOCK
- /* Test for lock before becoming daemon */
+ return ERR1("Failed to lseek pidfile '%s', errno: %d",
+ pidfile_name, errno);
+
+ /* Check that file can be locked */
if(lockf(pidfd, F_TLOCK, 0) == -1)
+ {
if(errno == EACCES || errno == EAGAIN)
return ERR1("Failed to lock pidfile '%s', already locked by "
- "pid=%ld, errno: %d", pidfile, daemonpid, errno);
+ "pid=%ld, errno: %d", pidfile_name, currpid, errno);
+ }
if(lockf(pidfd, F_ULOCK, 0) == -1)
- return ERR1("Failed to unlock pidfile '%s', errno: %d", pidfile, errno);
-#endif
+ return ERR1("Failed to unlock pidfile '%s', errno: %d",
+ pidfile_name, errno);
+
+ *pidfd_ret = pidfd;
return 0;
}
-int my_daemon_files()
+
+static int
+do_files(const char *pidfile_name, int pidfd, int logfd)
{
- int n;
- char buf[64];
- /* Running in child process */
- daemonpid= getpid();
-#ifdef F_TLOCK
- /* Lock the lock file (likely to succeed due to test above) */
- if(lockf(pidfd, F_LOCK, 0) == -1)
- return ERR1("Failed to lock pidfile '%s', errno: %d", pidfile, errno);
-#endif
-#ifndef _WIN32
- /* Become process group leader */
- if(setsid() == -1)
- return ERR1("Failed to setsid, errno: %d", errno);
-#endif
+ /* Lock the lock file */
+ if (lockf(pidfd, F_LOCK, 0) == -1)
+ return ERR1("Failed to lock pidfile '%s', errno: %d",
+ pidfile_name, errno);
+
/* Write pid to lock file */
- if(IF_WIN(_chsize, ftruncate)(pidfd, 0) == -1)
- return ERR1("Failed to truncate file '%s', errno: %d", pidfile, errno);
- n= my_sprintf(buf, (buf, "%ld", daemonpid));
- if(write(pidfd, buf, n) != n)
+ if (ftruncate(pidfd, 0) == -1)
+ return ERR1("Failed to truncate file '%s', errno: %d",
+ pidfile_name, errno);
+
+ char buf[32];
+ int length = my_snprintf(buf, sizeof(buf), "%ld", (long)getpid());
+ if (write(pidfd, buf, length) != length)
return ERR1("Failed to write pid to pidfile '%s', errno: %d",
- pidfile, errno);
+ pidfile_name, errno);
+
/* Do input/output redirections (assume fd 0,1,2 not in use) */
close(0);
- const char* fname=IF_WIN("nul:", "/dev/null");
- if(open(fname, O_RDONLY)==-1)
+ const char* fname = IF_WIN("nul:", "/dev/null");
+ if (open(fname, O_RDONLY) == -1)
return ERR1("Failed to open '%s', errno: %d", fname, errno);
+
#ifdef _WIN32 //no stdout/stderr on windows service
- *stdout= *stderr= *my_dlog;
+ *stdout= *stderr= *dlog_file;
#else
- if (logfd != 0)
+ if (logfd != -1)
{
dup2(logfd, 1);
dup2(logfd, 2);
close(logfd);
- my_dlog= stdout;
+ dlog_file= stdout;
}
#endif
+
return 0;
}
+
+
+int my_daemonize(const char* pidfile_name, const char *logfile_name)
+{
+ int pidfd = -1, logfd = -1;
+ if (check_files(pidfile_name, logfile_name, &pidfd, &logfd))
+ return 1;
+
+#ifndef _WIN32
+ pid_t child = fork();
+ if (child == -1)
+ return ERR1("fork failed, errno: %d, error: %s", errno, strerror(errno));
+
+ /* Exit if we are the parent */
+ if (child != 0)
+ exit(0);
+
+ /* Become process group leader */
+ if(setsid() == -1)
+ return ERR1("Failed to setsid, errno: %d", errno);
+
+#endif
+
+ if (do_files(pidfile_name, pidfd, logfd))
+ return 1;
+
+ return 0;
+}
+
+
+void my_daemon_exit(int status)
+{
+#ifdef _WIN32
+ /*
+ Stop by calling NtService::Stop if running
+ as a service(i.e g_shutdown_event created)
+ */
+ if (g_shutdown_event)
+ g_ntsvc.Stop();
+#endif
+ exit(status);
+}
=== modified file 'storage/ndb/src/mgmsrv/MgmtSrvr.hpp'
--- a/storage/ndb/src/mgmsrv/MgmtSrvr.hpp 2009-02-26 14:52:41 +0000
+++ b/storage/ndb/src/mgmsrv/MgmtSrvr.hpp 2009-03-13 09:03:33 +0000
@@ -132,7 +132,6 @@ public:
int print_full_config;
const char* configdir;
int verbose;
- MY_DAEMON_VARS0;
MgmtOpts() : configdir(MYSQLCLUSTERDIR) {};
int reload;
int initial;
=== modified file 'storage/ndb/src/mgmsrv/main.cpp'
--- a/storage/ndb/src/mgmsrv/main.cpp 2009-03-11 11:23:37 +0000
+++ b/storage/ndb/src/mgmsrv/main.cpp 2009-03-13 09:03:33 +0000
@@ -86,7 +86,6 @@ static MgmtSrvr::MgmtOpts opts;
static struct my_option my_long_options[] =
{
NDB_STD_OPTS("ndb_mgmd"),
- MY_DAEMON_LONG_OPTS(opts.)
{ "config-file", 'f', "Specify cluster configuration file",
(uchar**) &opts.config_filename, (uchar**) &opts.config_filename, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
@@ -153,9 +152,6 @@ static char **defaults_argv;
if in a windows service, don't want process to exit()
until cleanup of other threads is done
*/
-#ifdef _WIN32
-extern HANDLE g_shutdown_evt;
-#endif
static void mgmd_exit(int result)
{
g_eventLogger->close();
@@ -165,27 +161,13 @@ static void mgmd_exit(int result)
ndb_end(opt_ndb_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
-#ifdef _WIN32
- if(opts.service)
- SetEvent(g_shutdown_evt); // release stopper thread
- else
- exit(result);
-#else
- exit(result);
-#endif
+ my_daemon_exit(result);
}
-static int mgmd_run(void*);
-static int mgmd_start();
-static int save_argc_;
-static char** save_argv_;
-
-int main(int argc, char** argv)
+static int mgmd_main(int argc, char** argv)
{
NDB_INIT(argv[0]);
- save_argc_= argc;
- save_argv_= argv;
g_eventLogger->setCategory("MgmSrvr");
@@ -199,36 +181,27 @@ int main(int argc, char** argv)
opt_debug= IF_WIN("d:t:i:F:o,c:\\ndb_mgmd.trace",
"d:t:i:F:o,/tmp/ndb_mgmd.trace");
#endif
+
if ((ho_error=handle_options(&argc, &argv, my_long_options,
ndb_std_get_one_option)))
mgmd_exit(ho_error);
if (opts.interactive ||
opts.non_interactive ||
- opts.print_full_config ||
- IF_WIN(1,0)) {
+ opts.print_full_config) {
opts.daemon= 0;
}
#ifdef _WIN32
- int r=maybe_install_or_remove_service(save_argc_, save_argv_,
- (char*)opts.remove,
- (char*)opts.install,
- "MySQL Cluster Management Server");
- if(r!=-1)
- return r;
#ifdef _DEBUG
- /* it is impossible to attach a debugger to a starting service
- ** so it is necessary to log to a known place to diagnose
- ** problems. services don't have a stdout/stderr so the only
- ** way to write debug info is to a file.
- ** change this path if you don't have a c:\
- */
- if(opts.service) {
+ if (opts.daemon)
+ {
+ /* Write eventlog output to file for easier debugging */
g_eventLogger->createFileHandler("c:\\ndb_mgmd_debug.log");
- g_eventLogger->debug(NdbConfig_StdoutFileName(0));
- g_eventLogger->debug(NdbConfig_get_path(0));
- } else
+ g_eventLogger->info("StdoutFileName: %s", NdbConfig_StdoutFileName(0));
+ g_eventLogger->info("get_path: %s", NdbConfig_get_path(0));
+ g_eventLogger->info("GetCommandLine: %s", GetCommandLine());
+ }
#endif
#endif
/* Output to console initially */
@@ -250,115 +223,92 @@ int main(int argc, char** argv)
#if !defined NDB_WIN32
signal(SIGPIPE, SIG_IGN);
#endif
- return mgmd_start();
-}
-
-
-static int mgmd_stop()
-{
- g_StopServer= true;
- return 0;
-}
-
-static int mgmd_start()
-{
- g_eventLogger->info("NDB Cluster Management Server. %s", NDB_VERSION_STRING);
-
- mgm= new MgmtSrvr(opts, opt_connect_str);
- if (mgm == NULL) {
- g_eventLogger->critical("Out of memory, couldn't create MgmtSrvr");
- mgmd_exit(1);
- }
-
- /* Init mgm, load or fetch config */
- if (!mgm->init()) {
- delete mgm;
- mgmd_exit(1);
- }
-
- my_setwd(NdbConfig_get_path(0), MYF(0));
-#ifdef _WIN32
- g_eventLogger->debug("Command line '%s'",GetCommandLine());
-#endif
- if (IF_WIN(opts.service,opts.daemon))
+ while (!g_StopServer)
{
- g_eventLogger->debug("Service name: '%s'",IF_WIN(opts.service,""));
- NodeId localNodeId= mgm->getOwnNodeId();
- if (localNodeId == 0) {
- g_eventLogger->error("Couldn't get own node id");
- delete mgm;
- mgmd_exit(1);
- }
- struct MY_DAEMON thedaemon= {mgmd_run, mgmd_stop};
- char *lockfile= NdbConfig_PidFileName(localNodeId);
- char *logfile= NdbConfig_StdoutFileName(localNodeId);
- g_eventLogger->debug("to open %s,%s", lockfile, logfile);
- if (my_daemon_prefiles(lockfile, logfile)) {
- g_eventLogger->error("Couldn't access damon files, error: '%s'",
- my_daemon_error);
+ g_eventLogger->info("NDB Cluster Management Server. %s",
+ NDB_VERSION_STRING);
+
+ mgm= new MgmtSrvr(opts, opt_connect_str);
+ if (mgm == NULL) {
+ g_eventLogger->critical("Out of memory, couldn't create MgmtSrvr");
mgmd_exit(1);
}
- if(my_daemon_files()) {
- g_eventLogger->error("Couldn't create daemon files, error '%s'",
- my_daemon_error);
+
+ /* Init mgm, load or fetch config */
+ if (!mgm->init()) {
+ delete mgm;
mgmd_exit(1);
}
- if (my_daemon_run((char*)IF_WIN(opts.service,0),&thedaemon))
+ my_setwd(NdbConfig_get_path(0), MYF(0));
+
+ if (opts.daemon)
{
- g_eventLogger->error("Couldn't start as daemon, error: '%s'",
- my_daemon_error);
+ NodeId localNodeId= mgm->getOwnNodeId();
+ if (localNodeId == 0) {
+ g_eventLogger->error("Couldn't get own node id");
+ delete mgm;
+ mgmd_exit(1);
+ }
+
+ char *lockfile= NdbConfig_PidFileName(localNodeId);
+ char *logfile= NdbConfig_StdoutFileName(localNodeId);
+ if (my_daemonize(lockfile, logfile))
+ {
+ g_eventLogger->error("Couldn't start as daemon, error: '%s'",
+ my_daemon_error);
+ mgmd_exit(1);
+ }
+ }
+
+ /* Start mgm services */
+ if (!mgm->start()) {
+ delete mgm;
mgmd_exit(1);
}
- }
-#ifdef _WIN32
- if(opts.daemon) {
- g_eventLogger->error("No daemon mode on windows, use -i or --install "
- "to set up a service.");
- mgmd_exit(1);
- }
-#endif
- return mgmd_run(0);
-}
+ if (opts.interactive) {
+ int port= mgm->getPort();
+ BaseString con_str;
+ if(opts.bind_address)
+ con_str.appfmt("host=%s:%d", opts.bind_address, port);
+ else
+ con_str.appfmt("localhost:%d", port);
+ Ndb_mgmclient com(con_str.c_str(), 1);
+ while(!g_StopServer){
+ if (!read_and_execute(&com, "ndb_mgm> ", 1))
+ g_StopServer = true;
+ }
+ }
+ else {
+ while (!g_StopServer)
+ NdbSleep_MilliSleep(500);
+ }
-static int mgmd_run(void*)
-{
- if (!mgm->start()) { /* Start mgm services */
+ g_eventLogger->info("Shutting down server...");
delete mgm;
- mgmd_exit(1);
- }
+ g_eventLogger->info("Shutdown complete");
- if(opts.interactive) {
- int port= mgm->getPort();
- BaseString con_str;
- if(opts.bind_address)
- con_str.appfmt("host=%s:%d", opts.bind_address, port);
- else
- con_str.appfmt("localhost:%d", port);
- Ndb_mgmclient com(con_str.c_str(), 1);
- while(g_StopServer != true && read_and_execute(&com, "ndb_mgm> ", 1));
- }
- else {
- while(g_StopServer != true) {
- NdbSleep_MilliSleep(500);
+ if(g_RestartServer){
+ g_eventLogger->info("Restarting server...");
+ g_RestartServer= g_StopServer= false;
}
}
- g_eventLogger->info("Shutting down server...");
- delete mgm;
- g_eventLogger->info("Shutdown complete");
-
- if(g_RestartServer){
- g_eventLogger->info("Restarting server...");
- g_RestartServer= g_StopServer= false;
- int ex= mgmd_start();
- if(ex)
- mgmd_exit(ex);
- }
-
mgmd_exit(0);
return 0;
}
+
+static void mgmd_stop(void)
+{
+ g_StopServer= true;
+}
+
+
+int main(int argc, char** argv)
+{
+ return my_daemon_init(argc, argv, mgmd_main, mgmd_stop,
+ "ndb_mgmd", "MySQL Cluster Management Server");
+}
| Thread |
|---|
| • bzr commit into mysql-5.1-telco-6.4 branch (msvensson:2932) Bug#43559 | Magnus Svensson | 13 Mar |