fix(agent): Windows lifecycle lock and restart-mutex close the shutdown race
On Windows, OssecServiceStart() reports SERVICE_RUNNING before local_start() finishes building the wmodules list and spawning module threads, so the SCM can deliver SERVICE_CONTROL_STOP on its own thread at any point during startup, with nothing serializing it against local_start(). Depending on timing this let stop_wmodules() run against an empty/half-built module list, let local_start() keep spawning module threads after wm_shutdown_requested was already set, or raced cur_module->win_thread being written and read unsynchronized. A CRITICAL_SECTION (wm_lifecycle_lock) now makes "check the shutdown flag, build the wodle config, spawn every module thread" and "set the shutdown flag, walk the module list" mutually exclusive, held only across the fast, non-blocking parts of each -- never across a module's own Run(). Every Windows thread-based module entry point (skthread, logcollector_thread, win_module_thread, execd's win_exec_main) now checks startup_gate_wait_for_ready()'s result and skips its start routine on STARTUP_GATE_SHUTDOWN_REQUESTED instead of running it anyway. Two more pieces close the rest of the race: - CheckServiceRunning() treated only SERVICE_RUNNING as "running", so service-restart's wait-for-the-old-process-to-die loop gave up the instant the SCM reported SERVICE_STOP_PENDING -- long before the old process had actually finished stop_wmodules() -- and started a new process over it, racing the same SQLite files. It now treats anything other than SERVICE_STOPPED as still running, and the stop handler reports its checkpoint to the SCM every 2s while joining module threads so a slow shutdown doesn't read as hung. - Concurrent/overlapping service-restart invocations each independently fell through os_stop_service()'s "already stopping"/"already stopped" soft-success cases into their own stop-wait-start sequence, with nothing coordinating which one's stop/start actually won -- observed live to leave the service permanently SERVICE_STOPPED with no self-recovery and no error logged anywhere. run_service_restart() now serializes on a named, cross-process mutex (Global\WazuhAgentServiceRestart), with a bounded ~60s wait and a loud error log if that's ever exceeded. Issue: #38428
J
jr0me committed
91bfe51201a8e75d523b2fcc29b85fbd81b0dae5
Parent: 1e57485