Difference between revisions of "ShutdownProcess"

From ReactOS Wiki
Jump to: navigation, search
m
(Add location in ReactOS repository where are executed actions)
Line 8: Line 8:
  
 
* ExitWindowsEx() sends a message to CSRSS
 
* ExitWindowsEx() sends a message to CSRSS
 +
''Done in reactos/dll/win32/user32/misc/exit.c''
  
 
* CSRSS impersonates the caller and sends a message to a hidden WinLogon window
 
* CSRSS impersonates the caller and sends a message to a hidden WinLogon window
 +
''Done in reactos/subsystems/win32/csrss/win32csr/exitros.c : UserExitReactos''
  
 
* WinLogon checks if the caller has the required privileges
 
* WinLogon checks if the caller has the required privileges
 +
''Done in reactos/base/system/winlogon/sas.c : CheckPrivilegeForRequestedAction''
  
 
* WinLogon enters pending log-out state
 
* WinLogon enters pending log-out state
  
* WinLogon impersonates the interactive user and calls ExitWindowsEx() again,
+
* WinLogon impersonates the interactive user and calls ExitWindowsEx() again, passing some special internal flags
passing some special internal flags
+
''Done in reactos/base/system/winlogon/sas.c : LogoffShutdownThread''
  
* CSRSS loops over all processes of the interactive user (sorted by their
+
* CSRSS loops over all processes of the interactive user (sorted by their SetProcessShutdownParameters() level), sending WM_QUERYENDSESSION and WM_ENDSESSION messages to its top-level windows. If the messages aren't processed within the timeout period (registry key HKCU\Control Panel\Desktop\HungAppTimeout), CSRSS will put up a dialog box asking if the process should be terminated. Using the registry key HKCU\Control Panel\Desktop\AutoEndTask you can specify that the dialog box shouldn't be shown and CSRSS should just terminate the thread. If the the WM_ENDSESSION message is processed but the thread doesn't terminate within the timeout specified by HKCU\Control Panel\Desktop\WaitToKillAppTimeout CSRSS will terminate the thread. When all the top-level windows have been destroyed CSRSS will terminate the process. If the process is a console process, CSRSS will send a CTRL_LOGOFF_EVENT to the console control handler on logoff. No event is sent on shutdown. If the handler doesn't respond in time the same activities as for GUI apps (i.e. display dialog box etc) take place. This also happens if the handler returns TRUE.
SetProcessShutdownParameters() level), sending WM_QUERYENDSESSION and
+
''Done in reactos/subsystems/win32/csrss/win32csr/exitros.c : InternalExitReactos''
WM_ENDSESSION messages to its top-level windows. If the messages aren't
 
processed within the timeout period (registry key HKCU\Control Panel\Desktop\HungAppTimeout)
 
CSRSS will put up a dialog box asking if the process should be terminated.
 
Using the registry key HKCU\Control Panel\Desktop\AutoEndTask you can
 
specify that the dialog box shouldn't be shown and CSRSS should just
 
terminate the thread. If the the WM_ENDSESSION message is processed
 
but the thread doesn't terminate within the timeout specified by
 
HKCU\Control Panel\Desktop\WaitToKillAppTimeout CSRSS will terminate
 
the thread. When all the top-level windows have been destroyed CSRSS
 
will terminate the process.
 
If the process is a console process, CSRSS will send a CTRL_LOGOFF_EVENT
 
to the console control handler on logoff. No event is sent on shutdown.
 
If the handler doesn't respond in time the same activities as for GUI
 
apps (i.e. display dialog box etc) take place. This also happens if
 
the handler returns TRUE.
 
  
* This ends the processing for the first ExitWindowsEx() call from WinLogon.
+
* This ends the processing for the first ExitWindowsEx() call from WinLogon. Execution continues in WinLogon, which calls ExitWindowsEx() again to terminate COM processes in the interactive user's session.
Execution continues in WinLogon, which calls ExitWindowsEx() again to
 
terminate COM processes in the interactive user's session.
 
  
* WinLogon stops impersonating the interactive user (whos processes are
+
* WinLogon stops impersonating the interactive user (whos processes are all dead by now). and enters logged-out state
all dead by now). and enters logged-out state
+
''Done in reactos/base/system/winlogon/sas.c : LogoffShutdownThread''
  
* If the ExitWindowsEx() request was for a logoff, WinLogon sends a SAS
+
* If the ExitWindowsEx() request was for a logoff, WinLogon sends a SAS event (to display the "press ctrl+alt+del") to the GINA. WinLogon then waits for the GINA to send a SAS event to login.
event (to display the "press ctrl+alt+del") to the GINA. WinLogon then
+
''Done in reactos/base/system/winlogon/sas.c : HandleExitWindows''
waits for the GINA to send a SAS event to login.
 
  
* If the ExitWindowsEx() request was for shutdown/restart, WinLogon calls
+
* If the ExitWindowsEx() request was for shutdown/restart, WinLogon calls ExitWindowsEx() again in the system process context.
ExitWindowsEx() again in the system process context.
 
  
* CSRSS goes through the motions of sending WM_QUERYENDSESSION/WM_ENDSESSION
+
* CSRSS goes through the motions of sending WM_QUERYENDSESSION/WM_ENDSESSION to GUI processes running in the system process context but won't display dialog boxes or kill threads/processes. Same for console processes, using the CTRL_SHUTDOWN_EVENT. The Service Control Manager is one of these console processes and has a special timeout value WaitToKillServiceTimeout.
to GUI processes running in the system process context but won't display
 
dialog boxes or kill threads/processes. Same for console processes,
 
using the CTRL_SHUTDOWN_EVENT. The Service Control Manager is one of
 
these console processes and has a special timeout value WaitToKillServiceTimeout.
 
  
 
* WinLogon issues a "InitiateSystemShutdown" request to the SM (SMSS API # 1)
 
* WinLogon issues a "InitiateSystemShutdown" request to the SM (SMSS API # 1)
  
* the SM propagates the shutdown request to every environment subsystem it
+
* the SM propagates the shutdown request to every environment subsystem it started since bootstrap time (still active ones, of course)
started since bootstrap time (still active ones, of course)
 
  
* each environment subsystem, on shutdown request, releases every resource
+
* each environment subsystem, on shutdown request, releases every resource it aquired during its life (processes, memory etc), then dies
it aquired during its life (processes, memory etc), then dies
+
 
 +
* when every environment subsystem has gone to bed, the SM actually initiates the kernel and executive shutdown by calling NtShutdownSystem.
  
* when every environment subsystem has gone to bed, the SM actually initiates
 
the kernel and executive shutdown by calling NtShutdownSystem.
 
  
 
Although this is a pretty long list, I thought it wouldn't take long to implement. Boy, was I wrong :-) It's not really difficult, but it does use some stuff which isn't used very often by other parts of the system and which contained some buggy or unimplemented functions. On the bright side, I did learn a lot about security tokens, logon sessions etc. There are many details to work out, mostly by writing small test apps on MS Windows (Q: if you have an app with more than one top-level window, does each window get WM_QUERYENDSESSION notification? A: yes. Q: Are the timeouts reset for each notification or is there one big timeout for the process as a whole? A: one big timeout).
 
Although this is a pretty long list, I thought it wouldn't take long to implement. Boy, was I wrong :-) It's not really difficult, but it does use some stuff which isn't used very often by other parts of the system and which contained some buggy or unimplemented functions. On the bright side, I did learn a lot about security tokens, logon sessions etc. There are many details to work out, mostly by writing small test apps on MS Windows (Q: if you have an app with more than one top-level window, does each window get WM_QUERYENDSESSION notification? A: yes. Q: Are the timeouts reset for each notification or is there one big timeout for the process as a whole? A: one big timeout).
Line 76: Line 54:
  
  
The same boot switch can also be used to prompt for login name and password. Our GINA (Graphical Identification and Authentication, the component which is responsible for the winlogon user interface) dll can check for the presence of the switch and present either a console-mode login prompt or a GUI prompt. Of course, since we don't have any proper security anyway, this will also be a good time to implement auto-login (using the "DefaultUserName" registry value), as I don't want to type a (mostly useless at this moment) username/password every time I boot ReactOS for testing.
+
The same boot switch can also be used to prompt for login name and password. Our GINA (Graphical Identification and Authentication, the component which is responsible for the winlogon user interface) dll can check for the presence of the switch and present either a console-mode login prompt or a GUI prompt. Auto-login (using the "DefaultUserName" registry value) in implemented, as I don't want to type a (mostly useless at this moment) username/password every time I boot ReactOS for testing.

Revision as of 17:24, 4 August 2006

Taken from GvGs blog on login and shutdown processes.

Currently (Reactos 0.2.4 and lower) logout and shutdown isn't handled gracefully. User processes are not informed of the pending shutdown, only the kernel is properly shutdown. This needs to be rectified.

The collective minds of ros-kernel describe the logout/shutdown process as follows:

  • App (usually explorer) calls ExitWindowsEx()
  • ExitWindowsEx() sends a message to CSRSS

Done in reactos/dll/win32/user32/misc/exit.c

  • CSRSS impersonates the caller and sends a message to a hidden WinLogon window

Done in reactos/subsystems/win32/csrss/win32csr/exitros.c : UserExitReactos

  • WinLogon checks if the caller has the required privileges

Done in reactos/base/system/winlogon/sas.c : CheckPrivilegeForRequestedAction

  • WinLogon enters pending log-out state
  • WinLogon impersonates the interactive user and calls ExitWindowsEx() again, passing some special internal flags

Done in reactos/base/system/winlogon/sas.c : LogoffShutdownThread

  • CSRSS loops over all processes of the interactive user (sorted by their SetProcessShutdownParameters() level), sending WM_QUERYENDSESSION and WM_ENDSESSION messages to its top-level windows. If the messages aren't processed within the timeout period (registry key HKCU\Control Panel\Desktop\HungAppTimeout), CSRSS will put up a dialog box asking if the process should be terminated. Using the registry key HKCU\Control Panel\Desktop\AutoEndTask you can specify that the dialog box shouldn't be shown and CSRSS should just terminate the thread. If the the WM_ENDSESSION message is processed but the thread doesn't terminate within the timeout specified by HKCU\Control Panel\Desktop\WaitToKillAppTimeout CSRSS will terminate the thread. When all the top-level windows have been destroyed CSRSS will terminate the process. If the process is a console process, CSRSS will send a CTRL_LOGOFF_EVENT to the console control handler on logoff. No event is sent on shutdown. If the handler doesn't respond in time the same activities as for GUI apps (i.e. display dialog box etc) take place. This also happens if the handler returns TRUE.

Done in reactos/subsystems/win32/csrss/win32csr/exitros.c : InternalExitReactos

  • This ends the processing for the first ExitWindowsEx() call from WinLogon. Execution continues in WinLogon, which calls ExitWindowsEx() again to terminate COM processes in the interactive user's session.
  • WinLogon stops impersonating the interactive user (whos processes are all dead by now). and enters logged-out state

Done in reactos/base/system/winlogon/sas.c : LogoffShutdownThread

  • If the ExitWindowsEx() request was for a logoff, WinLogon sends a SAS event (to display the "press ctrl+alt+del") to the GINA. WinLogon then waits for the GINA to send a SAS event to login.

Done in reactos/base/system/winlogon/sas.c : HandleExitWindows

  • If the ExitWindowsEx() request was for shutdown/restart, WinLogon calls ExitWindowsEx() again in the system process context.
  • CSRSS goes through the motions of sending WM_QUERYENDSESSION/WM_ENDSESSION to GUI processes running in the system process context but won't display dialog boxes or kill threads/processes. Same for console processes, using the CTRL_SHUTDOWN_EVENT. The Service Control Manager is one of these console processes and has a special timeout value WaitToKillServiceTimeout.
  • WinLogon issues a "InitiateSystemShutdown" request to the SM (SMSS API # 1)
  • the SM propagates the shutdown request to every environment subsystem it started since bootstrap time (still active ones, of course)
  • each environment subsystem, on shutdown request, releases every resource it aquired during its life (processes, memory etc), then dies
  • when every environment subsystem has gone to bed, the SM actually initiates the kernel and executive shutdown by calling NtShutdownSystem.


Although this is a pretty long list, I thought it wouldn't take long to implement. Boy, was I wrong :-) It's not really difficult, but it does use some stuff which isn't used very often by other parts of the system and which contained some buggy or unimplemented functions. On the bright side, I did learn a lot about security tokens, logon sessions etc. There are many details to work out, mostly by writing small test apps on MS Windows (Q: if you have an app with more than one top-level window, does each window get WM_QUERYENDSESSION notification? A: yes. Q: Are the timeouts reset for each notification or is there one big timeout for the process as a whole? A: one big timeout).


So, where are we at this moment (end of August 2004)? Well, the first few steps are implemented (basically notifying Winlogon about the end session request). I'm working on the notification of GUI applications right now, that's almost finished (it already puts up the "End Program Now?" dialog box). Notification of console apps shouldn't be that hard because of code reuse. Process termination is easy (just call TerminateProcess()...). I'm not sure about the next step (terminating COM processes running in the interactive user's session). How do I recognize those processes? I'll probably chicken out of this one for now and just put in a FIXME, since we don't have any COM processes running at this point anyway... I estimate it will take another month or so to finish this.


For the future, I want to do some work on winlogon, since it is rather messy at the moment to put it nicely. One of the improvements of ReactOS over Windows is that we have the capability to start up in console mode. Only when a GUI app is started will the screen switch to graphics mode. I'd like to consolidate this by introducing a "/CONSOLE" boot switch. When this switch is not present on the boot line, Winlogon will load the program specified by the "Shell" registry value, normally this will be (ROS) explorer, causing the screen to switch to graphics mode. With the boot switch present, Winlogon will load the program specified by the "ConsoleShell" registry value (to be added), which normally will be cmd.exe running in "blue screen" mode.


The same boot switch can also be used to prompt for login name and password. Our GINA (Graphical Identification and Authentication, the component which is responsible for the winlogon user interface) dll can check for the presence of the switch and present either a console-mode login prompt or a GUI prompt. Auto-login (using the "DefaultUserName" registry value) in implemented, as I don't want to type a (mostly useless at this moment) username/password every time I boot ReactOS for testing.