mirror of
https://github.com/nginx/nginx.git
synced 2025-06-08 02:02:38 +08:00
Merge 948624aba7
into 5b8a5c08ce
This commit is contained in:
commit
504df8b4de
@ -183,6 +183,7 @@ ngx_module_t ngx_core_module = {
|
||||
static ngx_uint_t ngx_show_help;
|
||||
static ngx_uint_t ngx_show_version;
|
||||
static ngx_uint_t ngx_show_configure;
|
||||
static ngx_uint_t ngx_service = 0;
|
||||
static u_char *ngx_prefix;
|
||||
static u_char *ngx_error_log;
|
||||
static u_char *ngx_conf_file;
|
||||
@ -388,6 +389,56 @@ main(int argc, char *const *argv)
|
||||
}
|
||||
|
||||
|
||||
#ifdef NGX_WIN32
|
||||
static ngx_int_t
|
||||
ngx_install_windows_service()
|
||||
{
|
||||
wchar_t *install_commandline = NULL;
|
||||
wchar_t *i_opt_ptr = NULL;
|
||||
SC_HANDLE ScManagerHandle = NULL;
|
||||
SC_HANDLE NginxServiceHandle = NULL;
|
||||
|
||||
// Replace install commandline by service run commandline by
|
||||
// replacing the -i (install) option to a -w (windows service mode)
|
||||
install_commandline = _wcsdup(GetCommandLineW());
|
||||
i_opt_ptr = wcsstr(install_commandline, L" -i");
|
||||
i_opt_ptr[2] = 'w';
|
||||
printf("Installing NGINX service with commandline: %ls\n", install_commandline);
|
||||
|
||||
ScManagerHandle = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE);
|
||||
if (ScManagerHandle == NULL) {
|
||||
ngx_log_stderr(0, "OpenSCManagerW failed: errno == %d", ngx_errno);
|
||||
}
|
||||
|
||||
//"nginx" as service name is hardcoded is ngx_service : use a define ?
|
||||
NginxServiceHandle = CreateServiceW(ScManagerHandle,
|
||||
L"nginx",
|
||||
L"Nginx server service",
|
||||
SERVICE_ALL_ACCESS,
|
||||
SERVICE_WIN32_OWN_PROCESS,
|
||||
SERVICE_DEMAND_START, // Auto-start ? let user change it manually in windows interface ?
|
||||
SERVICE_ERROR_NORMAL,
|
||||
install_commandline,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL, //L"NT AUTHORITY\\NetworkService", ?
|
||||
NULL);
|
||||
|
||||
if (NginxServiceHandle == NULL) {
|
||||
ngx_log_stderr(0, "CreateServiceW failed: errno == %d", ngx_errno);
|
||||
CloseServiceHandle(ScManagerHandle);
|
||||
} else {
|
||||
printf("Service created !\n");
|
||||
}
|
||||
|
||||
CloseServiceHandle(NginxServiceHandle);
|
||||
CloseServiceHandle(ScManagerHandle);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
ngx_show_version_info(void)
|
||||
{
|
||||
@ -929,6 +980,18 @@ ngx_get_options(int argc, char *const *argv)
|
||||
ngx_log_stderr(0, "invalid option: \"-s %s\"", ngx_signal);
|
||||
return NGX_ERROR;
|
||||
|
||||
#ifdef NGX_WIN32
|
||||
case 'i':
|
||||
ngx_install_windows_service();
|
||||
exit(0); // Do something else ?
|
||||
|
||||
case 'w':
|
||||
// Run as windows service
|
||||
ngx_service = 1;
|
||||
goto next;
|
||||
|
||||
#endif
|
||||
|
||||
default:
|
||||
ngx_log_stderr(0, "invalid option: \"%c\"", *(p - 1));
|
||||
return NGX_ERROR;
|
||||
@ -1086,6 +1149,12 @@ ngx_process_options(ngx_cycle_t *cycle)
|
||||
cycle->log->log_level = NGX_LOG_INFO;
|
||||
}
|
||||
|
||||
#if NGX_WIN32
|
||||
if (ngx_service) {
|
||||
cycle->service = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
@ -82,6 +82,8 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
|
||||
cycle->log = log;
|
||||
cycle->old_cycle = old_cycle;
|
||||
|
||||
cycle->service = old_cycle->service;
|
||||
|
||||
cycle->conf_prefix.len = old_cycle->conf_prefix.len;
|
||||
cycle->conf_prefix.data = ngx_pstrdup(pool, &old_cycle->conf_prefix);
|
||||
if (cycle->conf_prefix.data == NULL) {
|
||||
|
@ -83,6 +83,7 @@ struct ngx_cycle_s {
|
||||
ngx_str_t error_log;
|
||||
ngx_str_t lock_file;
|
||||
ngx_str_t hostname;
|
||||
ngx_uint_t service;
|
||||
};
|
||||
|
||||
|
||||
|
@ -26,7 +26,11 @@ static ngx_thread_value_t __stdcall ngx_worker_thread(void *data);
|
||||
static ngx_thread_value_t __stdcall ngx_cache_manager_thread(void *data);
|
||||
static void ngx_cache_manager_process_handler(void);
|
||||
static ngx_thread_value_t __stdcall ngx_cache_loader_thread(void *data);
|
||||
static ngx_thread_value_t __stdcall ngx_service_thread(void *data);
|
||||
|
||||
/* TODO: ngx_service.h */
|
||||
|
||||
ngx_int_t ngx_service(ngx_log_t *log);
|
||||
|
||||
ngx_uint_t ngx_process;
|
||||
ngx_uint_t ngx_worker;
|
||||
@ -46,7 +50,7 @@ ngx_uint_t ngx_exiting;
|
||||
HANDLE ngx_master_process_event;
|
||||
char ngx_master_process_event_name[NGX_PROCESS_SYNC_NAME];
|
||||
|
||||
static HANDLE ngx_stop_event;
|
||||
HANDLE ngx_stop_event;
|
||||
static char ngx_stop_event_name[NGX_PROCESS_SYNC_NAME];
|
||||
static HANDLE ngx_quit_event;
|
||||
static char ngx_quit_event_name[NGX_PROCESS_SYNC_NAME];
|
||||
@ -68,6 +72,7 @@ ngx_master_process_cycle(ngx_cycle_t *cycle)
|
||||
ngx_int_t n;
|
||||
ngx_msec_t timer;
|
||||
ngx_uint_t live;
|
||||
ngx_tid_t servicetid;
|
||||
HANDLE events[MAXIMUM_WAIT_OBJECTS];
|
||||
|
||||
ngx_sprintf((u_char *) ngx_master_process_event_name,
|
||||
@ -116,6 +121,14 @@ ngx_master_process_cycle(ngx_cycle_t *cycle)
|
||||
|
||||
ngx_close_listening_sockets(cycle);
|
||||
|
||||
if (cycle->service){
|
||||
// Create only if this thread does not already exists ?
|
||||
if (ngx_create_thread(&servicetid, ngx_service_thread, NULL, cycle->log) != 0) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "Creating ngx_service_thread failed");
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
if (ngx_start_worker_processes(cycle, NGX_PROCESS_RESPAWN) == 0) {
|
||||
exit(2);
|
||||
}
|
||||
@ -754,7 +767,6 @@ ngx_worker_process_cycle(ngx_cycle_t *cycle, char *mevn)
|
||||
ngx_worker_process_exit(cycle);
|
||||
|
||||
failed:
|
||||
|
||||
exit(2);
|
||||
}
|
||||
|
||||
@ -981,6 +993,11 @@ ngx_cache_loader_thread(void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ngx_thread_value_t __stdcall
|
||||
ngx_service_thread(void *data)
|
||||
{
|
||||
return ngx_service((ngx_log_t*)data);
|
||||
}
|
||||
|
||||
void
|
||||
ngx_single_process_cycle(ngx_cycle_t *cycle)
|
||||
|
@ -4,131 +4,154 @@
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
#define NGX_SERVICE_CONTROL_SHUTDOWN 128
|
||||
#define NGX_SERVICE_CONTROL_REOPEN 129
|
||||
HANDLE ngx_stop_event; // Defined in src\os\win32\ngx_process_cycle.c
|
||||
|
||||
/*
|
||||
void LpserviceMainFunctiona(
|
||||
[in] DWORD dwNumServicesArgs,
|
||||
[in] LPSTR *lpServiceArgVectors
|
||||
)
|
||||
*/
|
||||
void WINAPI service_main(DWORD dwNumServicesArgs, LPSTR *lpServiceArgVectors);
|
||||
|
||||
SERVICE_TABLE_ENTRY st[] = {
|
||||
{ "nginx", service_main },
|
||||
/*
|
||||
|
||||
DWORD LphandlerFunctionEx(
|
||||
[in] DWORD dwControl,
|
||||
[in] DWORD dwEventType,
|
||||
[in] LPVOID lpEventData,
|
||||
[in] LPVOID lpContext
|
||||
)
|
||||
|
||||
*/
|
||||
DWORD WINAPI service_handler(DWORD control, DWORD type, void *data, void *ctx);
|
||||
|
||||
SERVICE_STATUS_HANDLE service = 0; // Put this field in ngx_cycle ?
|
||||
|
||||
SERVICE_TABLE_ENTRY service_table[] = {
|
||||
{ "nginx", service_main},
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_service(ngx_log_t *log)
|
||||
ngx_service()
|
||||
{
|
||||
/* primary thread */
|
||||
|
||||
/* StartServiceCtrlDispatcher() should be called within 30 seconds */
|
||||
|
||||
if (StartServiceCtrlDispatcher(st) == 0) {
|
||||
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
|
||||
if (StartServiceCtrlDispatcher(service_table) == 0) {
|
||||
ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno,
|
||||
"StartServiceCtrlDispatcher() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
service_main(u_int argc, char **argv)
|
||||
void WINAPI
|
||||
service_main(DWORD dwNumServicesArgs, LPSTR *lpServiceArgVectors)
|
||||
{
|
||||
SERVICE_STATUS status;
|
||||
SERVICE_STATUS_HANDLE service;
|
||||
|
||||
/* thread spawned by SCM */
|
||||
|
||||
service = RegisterServiceCtrlHandlerEx("nginx", service_handler, ctx);
|
||||
service = RegisterServiceCtrlHandlerEx("nginx", service_handler, NULL);
|
||||
if (service == INVALID_HANDLE_VALUE) {
|
||||
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
|
||||
ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno,
|
||||
"RegisterServiceCtrlHandlerEx() failed");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Use a more generic report_service_status ? */
|
||||
status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
||||
status.dwCurrentState = SERVICE_START_PENDING;
|
||||
status.dwControlsAccepted = SERVICE_ACCEPT_STOP
|
||||
|SERVICE_ACCEPT_PARAMCHANGE;
|
||||
status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
|
||||
status.dwWin32ExitCode = NO_ERROR;
|
||||
status.dwServiceSpecificExitCode = 0;
|
||||
status.dwCheckPoint = 1;
|
||||
status.dwWaitHint = 2000;
|
||||
|
||||
/* SetServiceStatus() should be called within 80 seconds */
|
||||
|
||||
if (SetServiceStatus(service, &status) == 0) {
|
||||
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
|
||||
ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno,
|
||||
"SetServiceStatus() failed");
|
||||
return;
|
||||
}
|
||||
|
||||
/* init */
|
||||
// Do we have any init to wait for ?
|
||||
// Init seems preety well advanced when the service thread is created
|
||||
|
||||
status.dwCurrentState = SERVICE_RUNNING;
|
||||
status.dwCheckPoint = 0;
|
||||
status.dwWaitHint = 0;
|
||||
|
||||
if (SetServiceStatus(service, &status) == 0) {
|
||||
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
|
||||
ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno,
|
||||
"SetServiceStatus() failed");
|
||||
return;
|
||||
}
|
||||
|
||||
/* call master or worker loop */
|
||||
}
|
||||
|
||||
/*
|
||||
* master should use event notification and look status
|
||||
* single should use iocp to get notifications from service handler
|
||||
*/
|
||||
int report_service_stop_status(DWORD dwCurrentState)
|
||||
{
|
||||
SERVICE_STATUS status;
|
||||
|
||||
status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
||||
status.dwCurrentState = dwCurrentState;
|
||||
status.dwControlsAccepted = 0;
|
||||
status.dwWin32ExitCode = NO_ERROR;
|
||||
status.dwServiceSpecificExitCode = 0;
|
||||
status.dwCheckPoint = 0;
|
||||
status.dwWaitHint = 0;
|
||||
|
||||
/* SetServiceStatus() should be called within 80 seconds */
|
||||
if (SetServiceStatus(service, &status) == 0) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
u_int
|
||||
service_handler(u_int control, u_int type, void *data, void *ctx)
|
||||
|
||||
DWORD WINAPI
|
||||
service_handler(DWORD control, DWORD type, void *data, void *ctx)
|
||||
{
|
||||
/* primary thread */
|
||||
|
||||
switch (control) {
|
||||
|
||||
case SERVICE_CONTROL_INTERROGATE:
|
||||
status = NGX_IOCP_INTERROGATE;
|
||||
break;
|
||||
switch (control) {
|
||||
|
||||
// case SERVICE_CONTROL_INTERROGATE:
|
||||
// status = NGX_IOCP_INTERROGATE;
|
||||
// break;
|
||||
//
|
||||
case SERVICE_CONTROL_STOP:
|
||||
status = NGX_IOCP_STOP;
|
||||
break;
|
||||
|
||||
case SERVICE_CONTROL_PARAMCHANGE:
|
||||
status = NGX_IOCP_RECONFIGURE;
|
||||
break;
|
||||
|
||||
case NGX_SERVICE_CONTROL_SHUTDOWN:
|
||||
status = NGX_IOCP_REOPEN;
|
||||
break;
|
||||
|
||||
case NGX_SERVICE_CONTROL_REOPEN:
|
||||
status = NGX_IOCP_REOPEN;
|
||||
report_service_stop_status(SERVICE_STOP_PENDING);
|
||||
if (SetEvent(ngx_stop_event) == 0) {
|
||||
ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno,
|
||||
"SetEvent(ngx_stop_event) failed");
|
||||
}
|
||||
report_service_stop_status(SERVICE_STOPPED);
|
||||
break;
|
||||
//
|
||||
// case SERVICE_CONTROL_PARAMCHANGE:
|
||||
// status = NGX_IOCP_RECONFIGURE;
|
||||
// break;
|
||||
//
|
||||
// case NGX_SERVICE_CONTROL_SHUTDOWN:
|
||||
// status = NGX_IOCP_REOPEN;
|
||||
// break;
|
||||
//
|
||||
// case NGX_SERVICE_CONTROL_REOPEN:
|
||||
// status = NGX_IOCP_REOPEN;
|
||||
// break;
|
||||
|
||||
default:
|
||||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
if (ngx_single) {
|
||||
if (PostQueuedCompletionStatus(iocp, ... status, ...) == 0) {
|
||||
err = ngx_errno;
|
||||
ngx_log_error(NGX_LOG_ALERT, log, err,
|
||||
"PostQueuedCompletionStatus() failed");
|
||||
return err;
|
||||
}
|
||||
|
||||
} else {
|
||||
Event
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user