mirror of
https://github.com/nginx/nginx.git
synced 2025-06-11 04:12:40 +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_help;
|
||||||
static ngx_uint_t ngx_show_version;
|
static ngx_uint_t ngx_show_version;
|
||||||
static ngx_uint_t ngx_show_configure;
|
static ngx_uint_t ngx_show_configure;
|
||||||
|
static ngx_uint_t ngx_service = 0;
|
||||||
static u_char *ngx_prefix;
|
static u_char *ngx_prefix;
|
||||||
static u_char *ngx_error_log;
|
static u_char *ngx_error_log;
|
||||||
static u_char *ngx_conf_file;
|
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
|
static void
|
||||||
ngx_show_version_info(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);
|
ngx_log_stderr(0, "invalid option: \"-s %s\"", ngx_signal);
|
||||||
return NGX_ERROR;
|
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:
|
default:
|
||||||
ngx_log_stderr(0, "invalid option: \"%c\"", *(p - 1));
|
ngx_log_stderr(0, "invalid option: \"%c\"", *(p - 1));
|
||||||
return NGX_ERROR;
|
return NGX_ERROR;
|
||||||
@ -1086,6 +1149,12 @@ ngx_process_options(ngx_cycle_t *cycle)
|
|||||||
cycle->log->log_level = NGX_LOG_INFO;
|
cycle->log->log_level = NGX_LOG_INFO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if NGX_WIN32
|
||||||
|
if (ngx_service) {
|
||||||
|
cycle->service = 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return NGX_OK;
|
return NGX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,6 +82,8 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
|
|||||||
cycle->log = log;
|
cycle->log = log;
|
||||||
cycle->old_cycle = old_cycle;
|
cycle->old_cycle = old_cycle;
|
||||||
|
|
||||||
|
cycle->service = old_cycle->service;
|
||||||
|
|
||||||
cycle->conf_prefix.len = old_cycle->conf_prefix.len;
|
cycle->conf_prefix.len = old_cycle->conf_prefix.len;
|
||||||
cycle->conf_prefix.data = ngx_pstrdup(pool, &old_cycle->conf_prefix);
|
cycle->conf_prefix.data = ngx_pstrdup(pool, &old_cycle->conf_prefix);
|
||||||
if (cycle->conf_prefix.data == NULL) {
|
if (cycle->conf_prefix.data == NULL) {
|
||||||
|
@ -83,6 +83,7 @@ struct ngx_cycle_s {
|
|||||||
ngx_str_t error_log;
|
ngx_str_t error_log;
|
||||||
ngx_str_t lock_file;
|
ngx_str_t lock_file;
|
||||||
ngx_str_t hostname;
|
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 ngx_thread_value_t __stdcall ngx_cache_manager_thread(void *data);
|
||||||
static void ngx_cache_manager_process_handler(void);
|
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_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_process;
|
||||||
ngx_uint_t ngx_worker;
|
ngx_uint_t ngx_worker;
|
||||||
@ -46,7 +50,7 @@ ngx_uint_t ngx_exiting;
|
|||||||
HANDLE ngx_master_process_event;
|
HANDLE ngx_master_process_event;
|
||||||
char ngx_master_process_event_name[NGX_PROCESS_SYNC_NAME];
|
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 char ngx_stop_event_name[NGX_PROCESS_SYNC_NAME];
|
||||||
static HANDLE ngx_quit_event;
|
static HANDLE ngx_quit_event;
|
||||||
static char ngx_quit_event_name[NGX_PROCESS_SYNC_NAME];
|
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_int_t n;
|
||||||
ngx_msec_t timer;
|
ngx_msec_t timer;
|
||||||
ngx_uint_t live;
|
ngx_uint_t live;
|
||||||
|
ngx_tid_t servicetid;
|
||||||
HANDLE events[MAXIMUM_WAIT_OBJECTS];
|
HANDLE events[MAXIMUM_WAIT_OBJECTS];
|
||||||
|
|
||||||
ngx_sprintf((u_char *) ngx_master_process_event_name,
|
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);
|
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) {
|
if (ngx_start_worker_processes(cycle, NGX_PROCESS_RESPAWN) == 0) {
|
||||||
exit(2);
|
exit(2);
|
||||||
}
|
}
|
||||||
@ -754,7 +767,6 @@ ngx_worker_process_cycle(ngx_cycle_t *cycle, char *mevn)
|
|||||||
ngx_worker_process_exit(cycle);
|
ngx_worker_process_exit(cycle);
|
||||||
|
|
||||||
failed:
|
failed:
|
||||||
|
|
||||||
exit(2);
|
exit(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -981,6 +993,11 @@ ngx_cache_loader_thread(void *data)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ngx_thread_value_t __stdcall
|
||||||
|
ngx_service_thread(void *data)
|
||||||
|
{
|
||||||
|
return ngx_service((ngx_log_t*)data);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ngx_single_process_cycle(ngx_cycle_t *cycle)
|
ngx_single_process_cycle(ngx_cycle_t *cycle)
|
||||||
|
@ -4,131 +4,154 @@
|
|||||||
* Copyright (C) Nginx, Inc.
|
* Copyright (C) Nginx, Inc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <ngx_config.h>
|
||||||
|
#include <ngx_core.h>
|
||||||
|
|
||||||
#define NGX_SERVICE_CONTROL_SHUTDOWN 128
|
#define NGX_SERVICE_CONTROL_SHUTDOWN 128
|
||||||
#define NGX_SERVICE_CONTROL_REOPEN 129
|
#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 }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
ngx_int_t
|
ngx_int_t
|
||||||
ngx_service(ngx_log_t *log)
|
ngx_service()
|
||||||
{
|
{
|
||||||
/* primary thread */
|
/* primary thread */
|
||||||
|
|
||||||
/* StartServiceCtrlDispatcher() should be called within 30 seconds */
|
/* StartServiceCtrlDispatcher() should be called within 30 seconds */
|
||||||
|
|
||||||
if (StartServiceCtrlDispatcher(st) == 0) {
|
if (StartServiceCtrlDispatcher(service_table) == 0) {
|
||||||
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
|
ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno,
|
||||||
"StartServiceCtrlDispatcher() failed");
|
"StartServiceCtrlDispatcher() failed");
|
||||||
return NGX_ERROR;
|
return NGX_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NGX_OK;
|
return NGX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void WINAPI
|
||||||
service_main(u_int argc, char **argv)
|
service_main(DWORD dwNumServicesArgs, LPSTR *lpServiceArgVectors)
|
||||||
{
|
{
|
||||||
SERVICE_STATUS status;
|
SERVICE_STATUS status;
|
||||||
SERVICE_STATUS_HANDLE service;
|
|
||||||
|
|
||||||
/* thread spawned by SCM */
|
/* thread spawned by SCM */
|
||||||
|
service = RegisterServiceCtrlHandlerEx("nginx", service_handler, NULL);
|
||||||
service = RegisterServiceCtrlHandlerEx("nginx", service_handler, ctx);
|
|
||||||
if (service == INVALID_HANDLE_VALUE) {
|
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");
|
"RegisterServiceCtrlHandlerEx() failed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Use a more generic report_service_status ? */
|
||||||
status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
||||||
status.dwCurrentState = SERVICE_START_PENDING;
|
status.dwCurrentState = SERVICE_START_PENDING;
|
||||||
status.dwControlsAccepted = SERVICE_ACCEPT_STOP
|
status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
|
||||||
|SERVICE_ACCEPT_PARAMCHANGE;
|
|
||||||
status.dwWin32ExitCode = NO_ERROR;
|
status.dwWin32ExitCode = NO_ERROR;
|
||||||
status.dwServiceSpecificExitCode = 0;
|
status.dwServiceSpecificExitCode = 0;
|
||||||
status.dwCheckPoint = 1;
|
status.dwCheckPoint = 1;
|
||||||
status.dwWaitHint = 2000;
|
status.dwWaitHint = 2000;
|
||||||
|
|
||||||
/* SetServiceStatus() should be called within 80 seconds */
|
/* SetServiceStatus() should be called within 80 seconds */
|
||||||
|
|
||||||
if (SetServiceStatus(service, &status) == 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");
|
"SetServiceStatus() failed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* init */
|
/* 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.dwCurrentState = SERVICE_RUNNING;
|
||||||
status.dwCheckPoint = 0;
|
status.dwCheckPoint = 0;
|
||||||
status.dwWaitHint = 0;
|
status.dwWaitHint = 0;
|
||||||
|
|
||||||
if (SetServiceStatus(service, &status) == 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");
|
"SetServiceStatus() failed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* call master or worker loop */
|
}
|
||||||
|
|
||||||
/*
|
int report_service_stop_status(DWORD dwCurrentState)
|
||||||
* master should use event notification and look status
|
{
|
||||||
* single should use iocp to get notifications from service handler
|
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) {
|
||||||
|
|
||||||
switch (control) {
|
|
||||||
|
|
||||||
case SERVICE_CONTROL_INTERROGATE:
|
|
||||||
status = NGX_IOCP_INTERROGATE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
// case SERVICE_CONTROL_INTERROGATE:
|
||||||
|
// status = NGX_IOCP_INTERROGATE;
|
||||||
|
// break;
|
||||||
|
//
|
||||||
case SERVICE_CONTROL_STOP:
|
case SERVICE_CONTROL_STOP:
|
||||||
status = NGX_IOCP_STOP;
|
report_service_stop_status(SERVICE_STOP_PENDING);
|
||||||
break;
|
if (SetEvent(ngx_stop_event) == 0) {
|
||||||
|
ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno,
|
||||||
case SERVICE_CONTROL_PARAMCHANGE:
|
"SetEvent(ngx_stop_event) failed");
|
||||||
status = NGX_IOCP_RECONFIGURE;
|
}
|
||||||
break;
|
report_service_stop_status(SERVICE_STOPPED);
|
||||||
|
|
||||||
case NGX_SERVICE_CONTROL_SHUTDOWN:
|
|
||||||
status = NGX_IOCP_REOPEN;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NGX_SERVICE_CONTROL_REOPEN:
|
|
||||||
status = NGX_IOCP_REOPEN;
|
|
||||||
break;
|
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:
|
default:
|
||||||
return ERROR_CALL_NOT_IMPLEMENTED;
|
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;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user