| /* | |
| * Copyright (C) Igor Sysoev | |
| */ | |
| #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() shouxpdl 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; | |
| } |