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.