Re: Avoid nested SIGINT handling
On 11/12/21, Mladen Gogala via Python-list wrote: > On Thu, 11 Nov 2021 17:22:15 +1100, Chris Angelico wrote: > >> Threads aren't the point here - signals happen immediately. > > [snip: description of POSIX signals] > > BTW, that's the case on both Unix/Linux systems and Windows systems. Windows is quite different. The base NT system has nothing that's closely analogous to POSIX signals. Its asynchronous procedure call (APC) capability is roughly similar to POSIX signals. Every thread has two APC queues, one for kernel-mode APCs and one for user-mode APCs. Unlike a POSIX signal, queuing an APC requires the address of a function in the process of the target thread. This requires well-known or registered function targets. User-mode APCs can be queued to a thread via QueueUserAPC(). Unless forced, they execute when the thread does an alertable wait. Another similar feature is a window message. A thread that uses any window-manager function is converted to a GUI thread with a message queue. A thread's window message queue is typically processed during a GetMessage() or PeekMessage() call. A message can be queued directly to a thread via PostThreadMessage(), provided it's a GUI thread. There's an overlap between Windows exceptions and POSIX signals. Exceptions get raised either from the kernel or RaiseException(). Exceptions have stack based handlers that are set via Microsoft's extended C __try/__except and __try/__finally statements. Process-wide exception handlers can also be set via AddVectoredExceptionHandler() and SetUnhandledExceptionFilter(). Windows also has console control events, which the console host (conhost.exe or openconsole.exe) sends to process groups that are connected to the hosted session (i.e. a TUI window/tab on a GUI desktop). The console host generates these events in response to typing Ctrl+C (cancel) or Ctrl+Break in the window/tab, closing the window/tab, user logoff, and system shutdown. CTRL_C_EVENT (0) CTRL_BREAK_EVENT (1) CTRL_CLOSE_EVENT (2) CTRL_LOGOFF_EVENT (5) CTRL_SHUTDOWN_EVENT (6) The Ctrl+C and Ctrl+Break events can also be generated for a process group via GenerateConsoleCtrlEvent(ctrlEvent, processGroupId). There's no thread or process queue for console control events. To deliver an event, the console host sends a message to the Windows session server (csrss.exe) that contains the control event number and one or more target processes. The session server creates a new thread in each target process. For example, if the user presses Ctrl+C five times sequentially in the console window, csrss.exe creates five threads in every process that's attached to the console. This thread injection is so different from POSIX signals that I hesitate to group it with signal-like features. A console control thread begins executing at the CtrlRoutine() function in kernelbase.dll. It sequentially iterates the list of registered handlers. Each is called with the given control event. If a handler returns TRUE (i.e. handled), the control thread exits. If no handler returns TRUE, the default handler is called, which exits the process with the exit code STATUS_CONTROL_C_EXIT (0xC13A). A inheritable flag can be set to disable CTRL_C_EVENT, such that CtrlRoutine() basically does nothing for this event. For CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT, and CTRL_SHUTDOWN_EVENT, the process must be terminated after the configured timeout, which is 5 seconds in a default setup. The process can exit gracefully of its own accord before the timeout. The C runtime library in Windows emulates some signals that are required by the language standard. The following two are emulated for C raise() and abort(): SIGABRT - abort, abnormal termination SIGTERM - terminate The following three are based on an exception handler: SIGSEGV - segmentation violation SIGILL - illegal/invalid instruction SIGFPE - floating point exception The following two are based on a console control event handler (SIGBREAK is non-standard): SIGINT - interrupt SIGBREAK - break, close, logoff, shutdown For SIGINT and SIGBREAK, the C runtime uses CTRL_C_EVENT and CTRL_BREAK_EVENT. It also maps SIGBREAK to CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT, and CTRL_SHUTDOWN_EVENT. But Python's C signal handler just sets a flag and returns, so SIGBREAK due to those events can't be handled with Python's signal module. The process gets terminated long before the main thread can call Python's registered SIGBREAK handler. -- https://mail.python.org/mailman/listinfo/python-list
Re: Avoid nested SIGINT handling
On Sun, Nov 14, 2021 at 4:42 AM Mladen Gogala via Python-list wrote: > > On Thu, 11 Nov 2021 17:22:15 +1100, Chris Angelico wrote: > > > Threads aren't the point here - signals happen immediately. > > Actually, signals are not delivered immediately. Signals are delivered > the next time the process gets its turn on CPU. The process scheduler > will make process runnable and the process will check for any pending > signals first and will execute the handler. It is possible to have > several SIGINT signals pending, for instance when I nervously press ctrl- > C several times. However, signals are not processed as a part of the > normal flow of the process and are processed sequentially.. When the > process finds a pending signal, it executes the registered signal > handler. It's always the same signal handler, unless signal handler is > changed within the signal handler. After the signals are delivered, the > process continues its normal operation until its CPU quantum expires or > until initiates a synchronous I/O operation, as is the case with all > normal read operations. > BTW, that's the case on both Unix/Linux systems and Windows systems. > Maybe at the C level, but none of that happens in Python :) There's a very very small signal handler in CPython that just sets a flag and then handles things separately. ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Avoid nested SIGINT handling
On Thu, 11 Nov 2021 17:22:15 +1100, Chris Angelico wrote: > Threads aren't the point here - signals happen immediately. Actually, signals are not delivered immediately. Signals are delivered the next time the process gets its turn on CPU. The process scheduler will make process runnable and the process will check for any pending signals first and will execute the handler. It is possible to have several SIGINT signals pending, for instance when I nervously press ctrl- C several times. However, signals are not processed as a part of the normal flow of the process and are processed sequentially.. When the process finds a pending signal, it executes the registered signal handler. It's always the same signal handler, unless signal handler is changed within the signal handler. After the signals are delivered, the process continues its normal operation until its CPU quantum expires or until initiates a synchronous I/O operation, as is the case with all normal read operations. BTW, that's the case on both Unix/Linux systems and Windows systems. -- Mladen Gogala Database Consultant https://dbwhisperer.wordpress.com -- https://mail.python.org/mailman/listinfo/python-list
Re: Avoid nested SIGINT handling
Às 06:22 de 11/11/21, Chris Angelico escreveu: > On Thu, Nov 11, 2021 at 5:01 PM Jon Ribbens via Python-list > wrote: >> >> On 2021-11-10, Paulo da Silva wrote: >>> Hi! >>> >>> How do I handle a SIGINT (or any other signal) avoid nesting? >> >> I don't think you need to. Python will only call signal handlers in >> the main thread, so a handler can't be executed while another handler >> is running anyway. > > Threads aren't the point here - signals happen immediately. > > Would it be easier to catch KeyboardInterrupt and do your processing > there, rather than actually catching SIGINT? > > I'd recommend just trying what you have, and seeing if it's reentrant. > My suspicion is that it isn't, on a technical level (the Python > function will be queued for when it's safe to call it - probably after > the next bytecode instruction), but that your own code will still need > to worry about reentrancy. > OK, thank you -- https://mail.python.org/mailman/listinfo/python-list
Re: Avoid nested SIGINT handling
On Thu, Nov 11, 2021 at 5:01 PM Jon Ribbens via Python-list wrote: > > On 2021-11-10, Paulo da Silva wrote: > > Hi! > > > > How do I handle a SIGINT (or any other signal) avoid nesting? > > I don't think you need to. Python will only call signal handlers in > the main thread, so a handler can't be executed while another handler > is running anyway. Threads aren't the point here - signals happen immediately. Would it be easier to catch KeyboardInterrupt and do your processing there, rather than actually catching SIGINT? I'd recommend just trying what you have, and seeing if it's reentrant. My suspicion is that it isn't, on a technical level (the Python function will be queued for when it's safe to call it - probably after the next bytecode instruction), but that your own code will still need to worry about reentrancy. ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Avoid nested SIGINT handling
Às 21:55 de 10/11/21, Jon Ribbens escreveu: > On 2021-11-10, Paulo da Silva wrote: >> Hi! >> >> How do I handle a SIGINT (or any other signal) avoid nesting? > > I don't think you need to. Python will only call signal handlers in > the main thread, so a handler can't be executed while another handler > is running anyway. > Do you mean that if I issue a ctrl+c while the previous one is "processing" it is held until, at least, the "processing" returns? -- https://mail.python.org/mailman/listinfo/python-list
Avoid nested SIGINT handling
Hi! How do I handle a SIGINT (or any other signal) avoid nesting? Does this work? class STATUS: InInt=False def SIGINT_handler(sn,f): if STATUS.InInt: return STATUS.InInt=True process_int() STATUS.InInt=False Thanks for any suggestions. Paulo -- https://mail.python.org/mailman/listinfo/python-list
Re: Avoid nested SIGINT handling
On 2021-11-10, Paulo da Silva wrote: > Hi! > > How do I handle a SIGINT (or any other signal) avoid nesting? I don't think you need to. Python will only call signal handlers in the main thread, so a handler can't be executed while another handler is running anyway. -- https://mail.python.org/mailman/listinfo/python-list