[GH-ISSUE #738] Application lock on tview.Application.QueueEvent #543

Open
opened 2026-03-04 01:05:53 +03:00 by kerem · 2 comments
Owner

Originally created by @bhbosman on GitHub (Jun 28, 2022).
Original GitHub issue: https://github.com/rivo/tview/issues/738

Hi,

First, thank you for publishing and maintaining this source code. I am using this on a console application and recently I connect this up to the golang SSH server implementation to run a ssh Channel terminal application, using tcell and tview.

My environment is as follows:

  • I create a SSH Channel over an TCP connection.
  • Create a tcell Terminal Screen
  • Connect tview.Application and Widgets to it
  • The terminal screen is updated from multiple channels, which is synchronized via tview.Application.QueueUpdate() and tview.Application.QueueUpdateDraw() methods
  • All of this work fine and I am very happy
  • When the SSH Channel terminates via CTRL-C, the tview.Application.Run exit, with no issues, and I start my SSH Channel unwinding process.
  • Sometimes my SSH Channel unwinds in full, and sometimes my SSH Channel unwinding mechanism fails.

After further investigation, I realized, that my SSH Channel unwinding fail as it is stuck in a tview.Application.QueueUpdate(). tview.Application.QueueUpdate() only returns when the queuedUpdate message has been processed and its done channel received a message. With tview.Application.Run() exited(correctly), there is no reading of the application.updates channel, which leaves me in a stale state.

A quick test case can show this. screen is an empty tcell.Screen implementation

`

app := tview.NewApplication()
app.SetScreen(&screen{})
app.SetRoot(tview.NewList(), true)
go func() {
	ev := tcell.NewEventKey(tcell.KeyCtrlC, 0, tcell.ModNone)
	app.QueueEvent(ev)
}()
err := app.Run()
if err != nil {
	return
}
go func() {
	app.QueueUpdate(
		func() {
			// this will never execute
		},
	)
	// this will never execute
}()

`

I would appreciate any feedback on this.

Regards
Brendan Bosman

Originally created by @bhbosman on GitHub (Jun 28, 2022). Original GitHub issue: https://github.com/rivo/tview/issues/738 Hi, First, thank you for publishing and maintaining this source code. I am using this on a console application and recently I connect this up to the golang SSH server implementation to run a ssh Channel terminal application, using `tcell` and `tview`. My environment is as follows: - I create a SSH Channel over an TCP connection. - Create a `tcell` Terminal Screen - Connect `tview.Application` and Widgets to it - The terminal screen is updated from multiple channels, which is synchronized via `tview.Application.QueueUpdate()` and `tview.Application.QueueUpdateDraw()` methods - All of this work fine and I am very happy - When the SSH Channel terminates via CTRL-C, the `tview.Application.Run` exit, with no issues, and I start my SSH Channel unwinding process. - Sometimes my SSH Channel unwinds in full, and sometimes my SSH Channel unwinding mechanism fails. After further investigation, I realized, that my SSH Channel unwinding fail as it is stuck in a `tview.Application.QueueUpdate()`. `tview.Application.QueueUpdate()` only returns when the `queuedUpdate` message has been processed and its `done` channel received a message. With `tview.Application.Run()` exited(correctly), there is no reading of the `application.updates` channel, which leaves me in a stale state. A quick test case can show this. `screen` is an empty `tcell.Screen` implementation ` app := tview.NewApplication() app.SetScreen(&screen{}) app.SetRoot(tview.NewList(), true) go func() { ev := tcell.NewEventKey(tcell.KeyCtrlC, 0, tcell.ModNone) app.QueueEvent(ev) }() err := app.Run() if err != nil { return } go func() { app.QueueUpdate( func() { // this will never execute }, ) // this will never execute }() ` I would appreciate any feedback on this. Regards Brendan Bosman
Author
Owner

@bhbosman commented on GitHub (Jun 29, 2022):

Hi

Created a pull request that will resolve this issue https://github.com/rivo/tview/pull/739

<!-- gh-comment-id:1169638699 --> @bhbosman commented on GitHub (Jun 29, 2022): Hi Created a pull request that will resolve this issue https://github.com/rivo/tview/pull/739
Author
Owner

@rivo commented on GitHub (Nov 12, 2022):

Your example uses screen{} which is not declared anywhere. But even with this line removed, the goroutine where you schedule the update is invoked after the application has already exited so of course, none of it executes.

I tried looking into your PR but it introduces a whole lot of other things, like contexts, new functions, and checks. Looks like quite a complex addition to the Applications class. (It's already a complex class so I'm very cautious adding more complexity to it.)

If you post a full, working, and brief code example that reproduces the issue, I will have another look.

<!-- gh-comment-id:1312477140 --> @rivo commented on GitHub (Nov 12, 2022): Your example uses `screen{}` which is not declared anywhere. But even with this line removed, the goroutine where you schedule the update is invoked _after_ the application has already exited so of course, none of it executes. I tried looking into your PR but it introduces a whole lot of other things, like contexts, new functions, and checks. Looks like quite a complex addition to the `Applications` class. (It's already a complex class so I'm very cautious adding more complexity to it.) If you post a full, working, and brief code example that reproduces the issue, I will have another look.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/tview#543
No description provided.