|  |  | 
|  | /* | 
|  | * Copyright (C) Igor Sysoev | 
|  | * Copyright (C) Nginx, Inc. | 
|  | */ | 
|  |  | 
|  |  | 
|  |  | 
|  | #define NGX_SERVICE_CONTROL_SHUTDOWN   128 | 
|  | #define NGX_SERVICE_CONTROL_REOPEN     129 | 
|  |  | 
|  |  | 
|  | SERVICE_TABLE_ENTRY st[] = { | 
|  | { "nginx", service_main }, | 
|  | { NULL, NULL } | 
|  | }; | 
|  |  | 
|  |  | 
|  | ngx_int_t | 
|  | ngx_service(ngx_log_t *log) | 
|  | { | 
|  | /* primary thread */ | 
|  |  | 
|  | /* StartServiceCtrlDispatcher() should be called within 30 seconds */ | 
|  |  | 
|  | if (StartServiceCtrlDispatcher(st) == 0) { | 
|  | ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, | 
|  | "StartServiceCtrlDispatcher() failed"); | 
|  | return NGX_ERROR; | 
|  | } | 
|  |  | 
|  | return NGX_OK; | 
|  | } | 
|  |  | 
|  |  | 
|  | void | 
|  | service_main(u_int argc, char **argv) | 
|  | { | 
|  | SERVICE_STATUS         status; | 
|  | SERVICE_STATUS_HANDLE  service; | 
|  |  | 
|  | /* thread spawned by SCM */ | 
|  |  | 
|  | service = RegisterServiceCtrlHandlerEx("nginx", service_handler, ctx); | 
|  | if (service == INVALID_HANDLE_VALUE) { | 
|  | ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, | 
|  | "RegisterServiceCtrlHandlerEx() failed"); | 
|  | return; | 
|  | } | 
|  |  | 
|  | status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; | 
|  | status.dwCurrentState = SERVICE_START_PENDING; | 
|  | status.dwControlsAccepted = SERVICE_ACCEPT_STOP | 
|  | |SERVICE_ACCEPT_PARAMCHANGE; | 
|  | 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, | 
|  | "SetServiceStatus() failed"); | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* init */ | 
|  |  | 
|  | status.dwCurrentState = SERVICE_RUNNING; | 
|  | status.dwCheckPoint = 0; | 
|  | status.dwWaitHint = 0; | 
|  |  | 
|  | if (SetServiceStatus(service, &status) == 0) { | 
|  | ngx_log_error(NGX_LOG_EMERG, 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 | 
|  | */ | 
|  |  | 
|  | } | 
|  |  | 
|  |  | 
|  | u_int | 
|  | service_handler(u_int control, u_int type, void *data, void *ctx) | 
|  | { | 
|  | /* primary thread */ | 
|  |  | 
|  | 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; | 
|  | 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; | 
|  | } |