Let StartServiceCtrlDispatcher handle services started other than with StartService (with patch)

Alexander Yaworsky yaworsky at migusoft.ru
Tue Aug 24 02:06:08 CDT 2004


Hello

In fact, the existing implementation of service subsystem in advapi32 is very poor and is sufficient only for very simple services
or test programs. I tried to launch oracle 7 database under wine and that trial has been failed. The main problem was inability of
parameter passing. Not only oracle -- most services require that. I did some improvements. Although I still cannot start database,
because its launcher, oradim, requires CreateRemoteThread, the listener service works well (although, it cannot be fully tested
because no database instance exists, but there is nothing suspicious in trace logs).
I even tried to submit a patch but it was silently ignored. Let me remind about this patch --
http://www.winehq.org/hypermail/wine-patches/2004/06/0174.html maybe it will be useful. If you have suggestions, I promise to
rewrite it as required ;))

Also, maybe the diagram shown below will be useful.

Thanks.

This simplified diagram shows interaction between three main
components of win32 service subsystem.

Service Control |   Service Control Manager   |   Service Program
    Program     |                             |
----------------+-----------------------------+-----------------------------
                |                             |
 StartService-----> LockServiceDatabase       |
                |   IF OWN_PROCES or          |
                |      (SHARE_PROCESS and Service
                |      Program is not running)|
                |   THEN                      |
                |                             |
                |   CreateProcess===============> ...
                |   wait for call to          |   initialization
                |   StartServiceCtrlDispatcher|   must not be longer
                |   timeout=30s               |   than 30 seconds
                |                             |   ...
                |   if wait timed out then    |   ...
                |   TerminateProcess          |   ...
      failure <---- UnlockServiceDatabase     |   ...
                |                             |   ...
                |   wait satisfied <============= StartServiceCtrlDispatcher
                |                             |
                |   END IF                    |
                |                             |
                |   CreateThread ***************> ServiceMain
                |   (or CreateRemoteThread    |   ...
                |    for SHARE_PROCESS;       |    *
                |    if SHARE_PROCESS then    |    *
                |    find entry in service    |    **********************
                |    table by service name;   |                         *
                |    if OWN_PROCESS then use  |                         *
                |    first entry)             |                         *
      success <---- UnlockServiceDatabase     |                         *
                |                             |                         *
                |   accept control requests   |                         *
                |                             |                         *
 ControlService---> request accepted ===========> ServiceControlHandler *
                |                             |   ...                   *
      status <----- return status <============== SetServiceStatus      *
                |                             |                         *
                |                             |                         *
                |                             |    **********************
                |                             |    *
                |                             |   ...
                |                             |   SetServiceStatus
                |   ExitThread <***************** (STOPPED)
                |   if Service Program has    |
                |   now only one thread       |
                |   return control from       |
                |   StartServiceCtrlDispatcher==> ...
                |                             |   ExitProcess

legend:

--- Service Control Program's thread
=== Service Program's main thread (control thread)
*** Service Program's service thread
OWN_PROCESS == SERVICE_WIN32_OWN_PROCESS
SHARE_PROCESS == SERVICE_WIN32_SHARE_PROCESS


Implementation.

completely win32-based

Two basic things:
a) The only time the service control manager requests ownership of the lock is when it is starting a service.
   (C) M$DN;
b) When StartService creates a new service process, it must pass arguments, or at least
   argv[0] - the service name - for ServiceMain across process boundary.

So, use the existence of shared memory object as lock indicator and the content of object for
passing service name.

Also we need a wait object for monitoring process startup. The call to StartServiceCtrlDispatcher will satisfy
wait condition.

A dedicated shared memory object is used for each service thread. It holds other arguments,
control requests and status.

Also we need mutex object for serialization of control requests and two wait objects for
serialization of service control program thread and service control handler thread.




More information about the wine-devel mailing list