Skip to content

Conversation

@juj
Copy link
Collaborator

@juj juj commented Oct 24, 2025

Improve Firefox browser process tracking by using the -wait-for-browser cmdline arg, and waiting longer for process startup.

Unfortunately -wait-for-browser is not enough to get rid of the process delta polling, since the process handle returned by subprocess.Popen() cannot be used to cascade the spawned Firefox windows.

Waiting for 2 seconds for Firefox startup was not enough, so make the wait time more conservative.

Add the detected processes to the list rather than replace, so that all process handles are retained.

It may be possible to remove the use of launch_browser_harness_with_proc_snapshot_workaround() for headless Firefox runs, but more testing will be needed to verify that.

…er cmdline arg, and waiting longer for process startup.
@sbc100
Copy link
Collaborator

sbc100 commented Oct 24, 2025

So what is -wait-for-browser supposed to actually do then?

@juj
Copy link
Collaborator Author

juj commented Oct 24, 2025

So what is -wait-for-browser supposed to actually do then?

It keeps the spawned process alive until the browser closes.

import subprocess, sys, time
proc = subprocess.Popen(['C:\\Program Files\\Mozilla Firefox\\firefox.exe', '-new-instance', '-wait-for-browser', 'https://wiki.mozilla.org/Firefox/CommandLineOptions'])

while True:
  if proc.poll() is not None:
    print('Browser process quit.')
    sys.exit(0)
  time.sleep(1)

With -wait-for-browser, the above test program prints 'Browser process quit.' when user closes the browser from the X button.

Without -wait-for-browser, the above test program immediately prints 'Browser process quit.' even when the browser window is still open.

@sbc100
Copy link
Collaborator

sbc100 commented Oct 24, 2025

I see. But it sounds like -wait-for-browser doesn't actually do what we need in that its still not enough just to kill the returned PID and wait for it to exit? i.e. its still possible, even with this flag, to have orphans firefox processes?

Is that a bug in -wait-for-browser?

Given that we still cannot just wait on the single PID, is there any advantage to using -wait-for-browser?

@sbc100
Copy link
Collaborator

sbc100 commented Oct 24, 2025

I think i'm not understanding the "since the process handle returned by subprocess.Popen() cannot be used to cascade the spawned Firefox windows." part

@juj
Copy link
Collaborator Author

juj commented Oct 24, 2025

But it sounds like -wait-for-browser doesn't actually do what we need in that its still not enough just to kill the returned PID and wait for it to exit?

It does. Seemingly so at least, in the small python test case that I posted above. Although I see CircleCI is giving some error, so I am running this on my CI also to test.

i.e. its still possible, even with this flag, to have orphans firefox processes?

I am hoping that would not be the case. That is what I referred with the comment

"It may be possible to remove the use of launch_browser_harness_with_proc_snapshot_workaround() for headless Firefox runs, but more testing will be needed to verify that."

"since the process handle returned by subprocess.Popen() cannot be used to cascade the spawned Firefox windows." part

The Emscripten test harness needs the process handles for two purposes:

  1. to be able to shut down the browser, and
  2. to be able to re-size and re-position the browser windows so they are cascaded on the desktop. Each browser has unique visible position on the desktop:
image

The comment "since the process handle returned by subprocess.Popen() cannot be used to cascade the spawned Firefox windows." means that even with -wait-for-browser, while we are able to solve 1., it is not able to solve 2.

@sbc100
Copy link
Collaborator

sbc100 commented Oct 24, 2025

Ok great. lgtm either way.

I guess we only need to keep the handle to the root processes then maybe we can do the cascading thing logically here in this function and avoid storing the extended process list in cls.browser_procs? i.e. for the purposes of kill in the browser we only need a single process now?

class FirefoxConfig:
data_dir_flag = '-profile '
default_flags = ('-new-instance',)
default_flags = ('-new-instance', '-wait-for-browser') if WINDOWS else ('-new-instance',)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably warrants a comment here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'll add one. I am still testing to understand why this is necessary.

@juj juj force-pushed the firefox_harness_fixes branch from 891901c to 65fa8c8 Compare October 25, 2025 17:42
@juj juj merged commit 22aee12 into emscripten-core:main Oct 27, 2025
34 checks passed
juj added a commit that referenced this pull request Oct 27, 2025
In previous PR #25644
I added `-wait-for-browser` use on Windows to help single-threaded
Windows runner not leave behind stale browser windows.

For some reason, it was not passing on CircleCI on Linux. Testing this
again to see what the failure is.

In local testing with a test script:

```py
import subprocess, sys, time

cmd = ['C:\\Program Files\\Mozilla Firefox\\firefox.exe', '-new-instance', '-profile', sys.argv[1], '-wait-for-browser', 'https://wiki.mozilla.org/Firefox/CommandLineOptions']
print('Launching browser: ' + ' '.join(cmd))
proc = subprocess.Popen(cmd)

for i in range(10):
  if proc.poll() is not None:
    print('Oops: process already quit, so we did not get a process handle to keep track of the browser instance.')
    sys.exit(0)
  time.sleep(1)

if proc.poll() is None:
  print('terminating browser process')
  proc.terminate()
time.sleep(2)
if proc.poll() is None:
  print('terminating did not work. killing browser process')
  proc.kill()

print('All done')
```

I am unable to find a behavioral difference between Windows and Linux.

So testing this out again on CircleCI.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants