FreeBSD/contrib/subversion/subversion/svnserve/winservice.c
/* If svnserve needs to run as a Win32 service, then we need to
   coordinate with the Service Control Manager (SCM) before
   continuing.  This function call registers the svnserve.exe process
   with the SCM, waits for the "start" command from the SCM (which
   will come very quickly), and confirms that those steps succeeded.

   After this call succeeds, the service should perform whatever work
   it needs to start the service, and then the service should call
   winservice_running() (if no errors occurred) or winservice_stop()
   (if something failed during startup). */
If svnserve needs to run as a Win32 service, then we need to
coordinate with the Service Control Manager (SCM) before
continuing.  This function call registers the svnserve.exe process
with the SCM, waits for the "start" command from the SCM (which
will come very quickly), and confirms that those steps succeeded.

After this call succeeds, the service should perform whatever work
it needs to start the service, and then the service should call
winservice_running() (if no errors occurred) or winservice_stop()
(if something failed during startup).
If svnserve needs to run as a Win32 service then we need to coordinate with the Service Control Manager ( SCM ) before continuing . This function call registers the svnserve . exe process with the SCM waits for the " start " command from the SCM ( which will come very quickly ) and confirms that those steps succeeded . After this call succeeds the service should perform whatever work it needs to start the service and then the service should call winservice_running () ( if no errors occurred ) or winservice_stop () ( if something failed during startup ) .
svn_error_t *
winservice_start(void)
{
  HANDLE handles[2];
  DWORD thread_id;
  DWORD error_code;
  apr_status_t apr_status;
  DWORD wait_status;
  dbg_print("winservice_start: starting svnserve as a service...\r\n");
  ZeroMemory(&winservice_status, sizeof(winservice_status));
  winservice_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  winservice_status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
  winservice_status.dwCurrentState = SERVICE_STOPPED;
  winservice_start_event = CreateEvent(NULL, FALSE, FALSE, NULL);
  if (winservice_start_event == NULL)
    {
      apr_status = apr_get_os_error();
      return svn_error_wrap_apr(apr_status,
                                _("Failed to create winservice_start_event"));
    }
  winservice_dispatcher_thread =
    (HANDLE)CreateThread(NULL, 0, winservice_dispatcher_thread_routine,
                         NULL, 0, &thread_id);
  if (winservice_dispatcher_thread == NULL)
    {
      apr_status = apr_get_os_error();
      winservice_cleanup();
      return svn_error_wrap_apr(apr_status,
                                _("The service failed to start"));
    }
  handles[0] = winservice_start_event;
  handles[1] = winservice_dispatcher_thread;
  wait_status = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
  switch (wait_status)
    {
    case WAIT_OBJECT_0:
      dbg_print("winservice_start: service is now starting\r\n");
      CloseHandle(winservice_start_event);
      winservice_start_event = NULL;
      atexit(winservice_atexit);
      return SVN_NO_ERROR;
    case WAIT_OBJECT_0+1:
      dbg_print("winservice_start: dispatcher thread has failed\r\n");
      if (GetExitCodeThread(winservice_dispatcher_thread, &error_code))
        {
          dbg_print("winservice_start: dispatcher thread failed\r\n");
          if (error_code == ERROR_SUCCESS)
            error_code = ERROR_INTERNAL_ERROR;
        }
      else
        {
          error_code = ERROR_INTERNAL_ERROR;
        }
      CloseHandle(winservice_dispatcher_thread);
      winservice_dispatcher_thread = NULL;
      winservice_cleanup();
      return svn_error_wrap_apr
        (APR_FROM_OS_ERROR(error_code),
         _("Failed to connect to Service Control Manager"));
    default:
      apr_status = apr_get_os_error();
      dbg_print("winservice_start: WaitForMultipleObjects failed!\r\n");
      winservice_cleanup();
      return svn_error_wrap_apr
        (apr_status, _("The service failed to start; an internal error"
                       " occurred while starting the service"));
    }
}
svn_error_t * winservice_start ( void ) { HANDLE handles [ 2 ] ; DWORD thread_id ; DWORD error_code ; apr_status_t apr_status ; DWORD wait_status ; dbg_print ( " \r \n " ) ; ZeroMemory ( & winservice_status , sizeof ( winservice_status ) ) ; winservice_status . dwServiceType = SERVICE_WIN32_OWN_PROCESS ; winservice_status . dwControlsAccepted = SERVICE_ACCEPT_STOP ; winservice_status . dwCurrentState = SERVICE_STOPPED ; winservice_start_event = CreateEvent ( NULL , FALSE , FALSE , NULL ) ; if ( winservice_start_event == NULL ) { apr_status = apr_get_os_error ( ) ; return svn_error_wrap_apr ( apr_status , _ ( " " ) ) ; } winservice_dispatcher_thread = ( HANDLE ) CreateThread ( NULL , 0 , winservice_dispatcher_thread_routine , NULL , 0 , & thread_id ) ; if ( winservice_dispatcher_thread == NULL ) { apr_status = apr_get_os_error ( ) ; winservice_cleanup ( ) ; return svn_error_wrap_apr ( apr_status , _ ( " " ) ) ; } handles [ 0 ] = winservice_start_event ; handles [ 1 ] = winservice_dispatcher_thread ; wait_status = WaitForMultipleObjects ( 2 , handles , FALSE , INFINITE ) ; switch ( wait_status ) { case WAIT_OBJECT_0 : dbg_print ( " \r \n " ) ; CloseHandle ( winservice_start_event ) ; winservice_start_event = NULL ; atexit ( winservice_atexit ) ; return SVN_NO_ERROR ; case WAIT_OBJECT_0 + 1 : dbg_print ( " \r \n " ) ; if ( GetExitCodeThread ( winservice_dispatcher_thread , & error_code ) ) { dbg_print ( " \r \n " ) ; if ( error_code == ERROR_SUCCESS ) error_code = ERROR_INTERNAL_ERROR ; } else { error_code = ERROR_INTERNAL_ERROR ; } CloseHandle ( winservice_dispatcher_thread ) ; winservice_dispatcher_thread = NULL ; winservice_cleanup ( ) ; return svn_error_wrap_apr ( APR_FROM_OS_ERROR ( error_code ) , _ ( " " ) ) ; default : apr_status = apr_get_os_error ( ) ; dbg_print ( " \r \n " ) ; winservice_cleanup ( ) ; return svn_error_wrap_apr ( apr_status , _ ( " " " " ) ) ; } }
If svnserve needs to run as a Win32 service, then we need to
coordinate with the Service Control Manager (SCM) before
continuing.
If svnserve needs to run as a Win32 service then we need to coordinate with the Service Control Manager ( SCM ) before continuing .
/* Create the event that will wake up this thread when the SCM
     creates the ServiceMain thread. */ /* Next, we wait for the "start" event to fire (meaning the service
     logic has successfully started), or for the dispatch thread to
     exit (meaning the service logic could not start). */ /* We no longer need the start event. */ /* Register our cleanup logic. */ /* The dispatcher thread exited without starting the service.
         This happens when the dispatcher fails to connect to the SCM. */ /* This should never happen! This indicates that our handles are
         broken, or some other highly unusual error.  There is nothing
         rational that we can do to recover. */