static VOID WINAPI service_main_loop()

in erts/etc/win32/erlsrv/erlsrv_service.c [707:966]


static VOID WINAPI service_main_loop(DWORD argc, wchar_t **argv){
  int waithint = 30000;
  int checkpoint = 1;
  RegEntry *keys;
  RegEntry *save_keys;
  ServerInfo srvi;
  HANDLE harr[2];
  FILETIME creationt,exitt,kernelt,usert;
  LONGLONG creationl,exitl,diffl;
  wchar_t event_name[MAX_PATH] = L"ErlSrv_";
  wchar_t executable_name[MAX_PATH];
#ifdef DEBUG
  wchar_t errorbuff[2048]; /* FIXME... */
#endif
  int success_wait = NO_SUCCESS_WAIT;

  real_service_name = argv[0];
  if(!pull_service_name()){
    log_error(L"Could not get Display name of erlang service.");
    set_stopped(ERROR_CANTREAD);
    return;
  }

  SetEnvironmentVariableW(SERVICE_ENV, service_name);

  wcsncat(event_name, service_name, MAX_PATH - wcslen(event_name));
  event_name[MAX_PATH - 1] = L'\0';

  if(!GetModuleFileNameW(NULL, executable_name, MAX_PATH)){
      log_error(L"Unable to retrieve module file name, " EXECUTABLE_ENV 
		L" will not be set.");
  } else {
      wchar_t quoted_exe_name[MAX_PATH+4];
      swprintf(quoted_exe_name, MAX_PATH+4, L"\"%s\"", executable_name);
      SetEnvironmentVariableW(EXECUTABLE_ENV, quoted_exe_name);
  }

  log_debug(L"Here we go, service_main_loop...");
  currentState = SERVICE_START_PENDING;
  InitializeCriticalSection(&crit);
  eventStop = CreateEvent(NULL,FALSE,FALSE,NULL); 
  if ((eventKillErlang = create_erlang_event(event_name)) != NULL) {
      srvi.event_name = event_name;
  } else {
      srvi.event_name = NULL;
  }
  statusHandle = RegisterServiceCtrlHandlerW(real_service_name, &handler);
  if(!statusHandle)
    return;
  set_start_pending(waithint,checkpoint);
  keys = get_keys(service_name);
  if(!keys){
    log_error(L"Could not get registry keys for erlang service.");
    set_stopped(ERROR_CANTREAD);
    return;
  }
  srvi.keys = keys;
  srvi.erl_stdin = NULL; 
  
  ++checkpoint;
  if(!start_a_service(&srvi)){
    log_error(L"Could not start erlang machine");
    set_stopped(ERROR_PROCESS_ABORTED);
    if (eventKillErlang != NULL) {
	CloseHandle(eventKillErlang);
    }
    free_keys(keys);
    return;
  }
  set_start_pending(waithint,checkpoint);
  set_running();
  success_wait = INITIAL_SUCCESS_WAIT;
  harr[0] = srvi.info.hProcess;
  harr[1] = eventStop;
  for(;;){
    DWORD ret;
    ret = WaitForMultipleObjects((DWORD) 2,
				 harr,
				 FALSE,
				 (success_wait == NO_SUCCESS_WAIT) ? 
				 INFINITE :
				 SUCCESS_WAIT_TIME);
    if(ret == WAIT_TIMEOUT){
      /* Just do the "success reporting" and continue */
      if(success_wait == INITIAL_SUCCESS_WAIT){
	log_info(L"Erlang service started successfully.");
      } else {
	log_warning(L"Erlang service restarted");
      }
      success_wait = NO_SUCCESS_WAIT;
      continue;
    }
    if(ret == WAIT_FAILED || (int)(ret-WAIT_OBJECT_0) >= 2){
      set_stopped(WAIT_FAILED);
      log_error(L"Internal error, could not wait for objects.");
      if (eventKillErlang != NULL) {
	  CloseHandle(eventKillErlang);
      }
      free_keys(keys);
      return;
    }
    ret -= WAIT_OBJECT_0;
    if(((int) ret) == 1){
      /* Stop service... */
      checkpoint = 2; /* 1 is taken by the handler */
      set_stop_pending(waithint,checkpoint);
      if(stop_erlang(&srvi,waithint,&checkpoint)){
	log_debug(L"Erlang machine is stopped");
	CloseHandle(eventStop);
	if (eventKillErlang != NULL) {
	    CloseHandle(eventKillErlang);
	}
	set_stopped(NO_ERROR);
	if(srvi.erl_stdin)
	  CloseHandle(srvi.erl_stdin);
	free_keys(keys);
	return;
      } else {
	log_warning(L"Unable to stop erlang service.");
	set_running();
	continue;
      }
    }
    /* Reload the registry keys, they may have changed. */
    save_keys = keys;
    keys = get_keys(service_name);
    if(!keys){
      log_error(L"Could not reload registry keys.");
      keys = srvi.keys = save_keys;
    } else {
#ifdef HARDDEBUG
      swprintf(errorbuff,2048,L"Reloaded the registry keys because %s stopped.",
	       service_name);
      log_debug(errorbuff);
#endif /* HARDDEBUG */
      free_keys(save_keys);
      srvi.keys = keys;
    }
    if(srvi.keys[OnFail].data.value == ON_FAIL_RESTART || 
       srvi.keys[OnFail].data.value == ON_FAIL_RESTART_ALWAYS){
      if(!GetProcessTimes(srvi.info.hProcess,&creationt,
			  &exitt,&kernelt,&usert)){
	DWORD rcode = GetLastError();
	log_error(L"Could not get process time of terminated process.");
	CloseHandle(srvi.info.hProcess);
	CloseHandle(srvi.info.hThread);
	CloseHandle(eventStop);
	if(srvi.erl_stdin)
	  CloseHandle(srvi.erl_stdin);
	set_stopped(rcode);
	if (eventKillErlang != NULL) {
	    CloseHandle(eventKillErlang);
	}
	free_keys(keys);
	return;
      }
      CloseHandle(srvi.info.hProcess);
      CloseHandle(srvi.info.hThread);
      if(srvi.erl_stdin)
	CloseHandle(srvi.erl_stdin);
      srvi.erl_stdin = NULL;
      memcpy(&creationl,&creationt,sizeof(FILETIME));
      memcpy(&exitl,&exitt,sizeof(FILETIME));
      diffl = exitl - creationl;
      diffl /= 10000000;
#ifdef DEBUG
      swprintf(errorbuff,2048,L"Process lived for %d seconds", (int) diffl);
      log_debug(errorbuff);
#endif      

      if(diffl > CYCLIC_RESTART_LIMIT || 
	 srvi.keys[OnFail].data.value == ON_FAIL_RESTART_ALWAYS){
	if(!start_a_service(&srvi)){
	  log_error(L"Unable to restart failed erlang service, aborting.");
	  CloseHandle(eventStop);
	  set_stopped(ERROR_PROCESS_ABORTED);
	  if (eventKillErlang != NULL) {
	      CloseHandle(eventKillErlang);
	  }
	  free_keys(keys);
	  return;
	}
	log_warning(L"Restarted erlang machine.");
	if(diffl <= CYCLIC_RESTART_LIMIT)
	  log_warning(L"Possible cyclic restarting of erlang machine.");
	success_wait = RESTART_SUCCESS_WAIT;
	harr[0] = srvi.info.hProcess;
      } else {
	if(success_wait == INITIAL_SUCCESS_WAIT){
	  log_error(L"Erlang machine stopped instantly "
		    L"(distribution name conflict?). "
		    L"The service is not restarted, ignoring OnFail option.");
	} else {
	  log_error(L"Erlang machine seems to die "
		    L"continously, not restarted.");
	}
	CloseHandle(eventStop);
	set_stopped(ERROR_PROCESS_ABORTED);
	if (eventKillErlang != NULL) {
	    CloseHandle(eventKillErlang);
	}
	free_keys(keys);
	return;
      }
    } else if(srvi.keys[OnFail].data.value == ON_FAIL_REBOOT){
      log_error(L"Rebooting because erlang machine stopped.");
      enable_privilege();
      if(!InitiateSystemShutdown("",NULL,0,TRUE,TRUE)){
	log_error(L"Failed to reboot!");
#ifdef HARDDEBUG
	{
	  wchar_t *mes;
	  FormatMessageW(
			 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
			 NULL,    
			 GetLastError(),
			 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
			 (LPWSTR) &mes,    
			 0,    
			 NULL );
	  log_debug(mes);
	  LocalFree(mes);
	}
#endif 
	CloseHandle(srvi.info.hProcess);
	CloseHandle(eventStop);
	if(srvi.erl_stdin != NULL)
	  CloseHandle(srvi.erl_stdin);
	set_stopped(NO_ERROR);
	if (eventKillErlang != NULL) {
	    CloseHandle(eventKillErlang);
	}
	free_keys(keys);
	return;
      }
    } else {
      DWORD ecode = NO_ERROR;
      if(success_wait == NO_SUCCESS_WAIT){
	log_warning(L"Erlang machine voluntarily stopped. "
		    L"The service is not restarted as OnFail "
		    L"is set to ignore.");
      } else {
	log_error(L"Erlang machine stopped instantly "
		  L"(distribution name conflict?). "
		  L"The service is not restarted as OnFail is set to ignore.");
	ecode = ERROR_PROCESS_ABORTED;
      }
      CloseHandle(srvi.info.hProcess);
      CloseHandle(eventStop);
      if(srvi.erl_stdin != NULL)
	CloseHandle(srvi.erl_stdin);
      set_stopped(ecode);
      if (eventKillErlang != NULL) {
	  CloseHandle(eventKillErlang);
      }
      free_keys(keys);
      return;
    }      
  }
}