Psreadline: OnIdle Doesn't Seem to Fire Until PowerShell is Not Idle

Created on 9 Oct 2019  ·  14Comments  ·  Source: PowerShell/PSReadLine

Environment data

PS version: 7.0.0-preview.4
PSReadline version: 2.0.0-beta5
os: Darwin Nick-Coxs-Macbook-Pro.local 18.7.0 Darwin Kernel Version 18.7.0: Tue Aug 20 16:57:14 PDT 2019; root:xnu-4903.271.2~2/RELEASE_X86_64 x86_64
PS file version: 7.0.0.0
HostName: ConsoleHost
BufferWidth: 238
BufferHeight: 59

Steps to reproduce or exception report

Without PSReadLine

❯ pwsh -nologo -noprofile
PS /Users/nick.cox> Remove-Module PSReadline
PS /Users/nick.cox> $null = Register-EngineEvent -SourceIdentifier PowerShell.OnIdle -Action {Write-Host  '*idle*'} -MaxTriggerCount 3
PS /Users/nick.cox> *idle*
*idle*
*idle*

With PSReadLine

❯ pwsh -nologo -noprofile
PS /Users/nick.cox> Get-Module PSReadline
ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Script     2.0.0      PSReadLine                          {Get-PSReadLineKeyHandler, Get-PSReadLineOption, Remove-PSReadLineKeyHandler, Set-PSReadLineKeyHandler…}

PS /Users/nick.cox> $null = Register-EngineEvent -SourceIdentifier PowerShell.OnIdle -Action {Write-Host  '*idle*'} -MaxTriggerCount 3
PS /Users/nick.cox> *idle*
# ... (nothing happens until I press a key)
a*idle*
aa*idle*

All 14 comments

What are you expecting differently, and how does it relate to PSReadline? To me, it seems to be working as one would expect. I almost immediately get the 'idle', once, as was requested.

Sorry, I didn't explain that very well.

What are you expecting differently

I would expect to almost immediately see *idle*, once, as was requested

how does it relate to PSReadline?

Here are the two scenarios:

Without PSReadLine

❯ pwsh -nologo -noprofile
PS /Users/nick.cox> Remove-Module PSReadline
PS /Users/nick.cox> $null = Register-EngineEvent -SourceIdentifier PowerShell.OnIdle -Action {Write-Host  '*idle*'} -MaxTriggerCount 1
PS /Users/nick.cox> *idle*

The event is triggered almost immediately, as one would expect.

With PSReadLine

❯ pwsh -nologo -noprofile
PS /Users/nick.cox> Get-Module PSReadline
ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Script     2.0.0      PSReadLine                          {Get-PSReadLineKeyHandler, Get-PSReadLineOption, Remove-PSReadLineKeyHandler, Set-PSReadLineKeyHandler…}

PS /Users/nick.cox> $null = Register-EngineEvent -SourceIdentifier PowerShell.OnIdle -Action {Write-Host  '*idle*'} -MaxTriggerCount 1
PS /Users/nick.cox> # nothing happens until I press a key

Do you see what I mean?

What operating system are you on? I'm pretty sure I tested this previously on Windows and it worked well (on beta4 and beta5).

@msftrncs I've just tested this on my Windows machine and can confirm that it seems fine there.

Does the above make sense? Is there anything else I can do to help you get to the bottom of this?

@msftrncs This is a bug/quirk with how System.Console works on non-Windows platforms (see #626 and dotnet/corefx#25036 for more details). There aren't any particularly good ways of solving this currently.

We could revisit calling the C# api directly from the console host instead of calling the PowerShell function.

I ran into difficulties when I tried that originally, but I don't recall what issues there were in invoking custom keybindings.

Right now the issue is that Console.ReadKey is blocking on one thread, and then on the pipeline thread cursor position is checked before triggering events. The call to ReadKey will hold corefx's internal lock on stdin, then the cursor position query will attempt to acquire that same lock (in core 3.0 it's not every time, but frequently enough that it's not a fix). That causes the pipeline thread to block until ReadKey completes. Afaict that wouldn't change if PSConsoleHostReadLine was skipped.

I think you discussed removing that cursor position check in the ReadKey timeout loop at one point. If nothing else queries cursor position that will work. I vaguely remember something in the general pipeline spin up/wind down code path that queries cursor position but I might be thinking of ConsoleHost. Though if an event handler needed to check cursor position it would still lock.

I was suggesting that if the console host calls the C# api directly, we could avoid having the pipeline thread be blocked completely - e.g. it could be on yet another thread.

That leaves the issue of invoking custom key handlers which is probably a solvable problem but I don't recall the precise issues I hit.

I cannot reproduce the issue on macOS with pwsh 7.0.0-preview.4 and PSReadLine 2.0.0-beta5.
*idle* shows up immediately after running the Register-EngineEvent command.
@nickcox Can you try 7.0.0-preview.4?

Oct-09-2019 13-40-02

👍Works for me on preview 4, @daxian-dbw

@daxian-dbw

On further investigation, it actually still isn't right. With preview 4 it seems to trigger the event exactly once.

Without PSReadLine

❯ pwsh -nologo -noprofile
PS /Users/nick.cox> Remove-Module PSReadline
PS /Users/nick.cox> $null = Register-EngineEvent -SourceIdentifier PowerShell.OnIdle -Action {Write-Host  '*idle*'} -MaxTriggerCount 3
PS /Users/nick.cox> *idle*
*idle*
*idle*

With PSReadLine

❯ pwsh -nologo -noprofile
PS /Users/nick.cox> Get-Module PSReadline
ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Script     2.0.0      PSReadLine                          {Get-PSReadLineKeyHandler, Get-PSReadLineOption, Remove-PSReadLineKeyHandler, Set-PSReadLineKeyHandler…}

PS /Users/nick.cox> $null = Register-EngineEvent -SourceIdentifier PowerShell.OnIdle -Action {Write-Host  '*idle*'} -MaxTriggerCount 3
PS /Users/nick.cox> *idle*
# ... (nothing happens until I press a key)
a*idle*
aa*idle*

Updated the repro steps.

Thanks. Should we update the environment data too then? Coz the updated repro steps don't correspond to what happens on the stated environment (PS version: 6.2.3).

Of course, please update the environment data. Thanks

@daxian-dbw For context, dotnet/corefx#36049 made it occur less frequently, but anytime the cache is invalidated then the scenario I described will resurface.

Was this page helpful?
0 / 5 - 0 ratings