|  | 
 | /* | 
 |  * 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; | 
 | } |