Why does loginwindow keep freezing in Mojave

bughangmojave

This is a follow-up to my previous question: Function keys stop working after a while in Mojave

The issue I had is that loginwindow kept freezing. In this Gist, the issue is explained in detail. The explanation can be found below.

macOS Mojave build >18A326g has a nasty issue.

Basically, loginwindow likes threads. It's so passionate about threads that
it will continue to collect threads endlessly. Now, the problem with such a
process collecting so many threads is that, as the owner of all processes
running under your account, if the process crashes, say goodbye to most of
macOS.

Well, this is exactly what happens. loginwindow freezes at 4096 threads and
causes most of macOS to become unstable or unusable. For example, most of the
menu items under the apple menu become useless, such as About This Mac or the
Sleep/Restart/Shut Down options. Some of the function/media keys stop working
as well, such as the brightness, keyboard backlight, and volume keys.

I also believe the log out option gets disabled too, but I haven't tested it.
However, if this is indeed the case, this means the only way to log out
reliably is using this script with the --kill option, which finds and kills
loginwindow for you.

loginwindow does indeed collect 4096 threads and then freeze. Every time. In fact, I built a notifier using JXA to warn me when corruption (threads / 4096) reaches over 90%.

That's beside the point, however. As far as I can tell, nobody else has the issue (either that or they never figured out why).

I've reported this issue to Apple 4 betas ago, but the issue's still here.

How do I figure out what's causing this issue? How do I prevent it?

Best Answer

I've noticed the exact same hanging loginwindow issue since upgrading to Mojave 10.14.5. As @Dev and some of the other responses pointed out, there are some common applications which seem to contribute to this. Little Snitch is the culprit in my case and have found the following solutions work best as a workaround. My system is also configured for automatic login.

The immediate solution to fix the hanging loginwindow is to ssh into the host which hangs and run this simple script (or one-liner) to stop loginwindow and then start it again using launchctl.

#!/bin/sh
sudo launchctl stop com.apple.loginwindow
sleep 2
sudo launchctl start com.apple.loginwindow

OR

sudo launchctl stop com.apple.loginwindow && sleep 2 && sudo launchctl start com.apple.loginwindow

The long-term workaround solution until Objective Development and/or Apple addresses this problematic behavior in their code is to instrument a launch daemon which executes a modified version of the above script at startup.

  1. Create script in /usr/local/bin named fixHang.sh

    sudo touch /usr/local/bin/fixHang.sh
    
  2. Edit the script and paste in the content below.

    sudo nano /usr/local/bin/fixHang.sh
    

    #!/bin/sh
    logFile="/Users/Michael/loginwindowdaemonscript.txt"
    echo "------------BOOT BEGIN $(date)----------"
    ustart=$(date -j -f "%a %b %d %T %Z %Y" "date" "+%s")
    timestamp=$(date)
    loginPIDChar=$(ps -ef | grep -v "grep" | grep "/usr/libexec/UserEventAgent (Aqua)" | awk $'{print $2}' | wc | awk $'{print $1}')
    loginPID=$(ps -ef | grep -v "grep" | grep "/usr/libexec/UserEventAgent (Aqua)" | awk $'{print $2}')
    echo "$(date) - START" >> "$logFile"
    echo "$(date) - loginwindow PID: $loginPIDWindow" >> "$logFile"
    echo "$(date) - UserEventAgentAqua PID: $loginPID" >> "$logFile"
    while [ "$loginPIDChar" == "0" ];
    do
            echo "$(date) - BEGIN LOOP" >> "$logFile"
            sleep 2
            echo "BEGIN CHECK" >> "$logFile"
            loginPIDChar=$(ps -ef | grep -v "grep" | grep "/usr/libexec/UserEventAgent (Aqua)" | awk $'{print $2}' | wc | awk $'{print $1}')
            loginWindowPID=$(pgrep loginwindow)
            echo "$loginWindowPID" >> "$logFile"
            echo "loginPIDChar = $loginPIDChar" >> "$logFile"
            if [ "$loginPIDChar" != 0 ];
            then
                    timestamp=$(date)
                    loginWindowPID=$(pgrep loginwindow)
                    echo "$timestamp - KILL PROCESS # $loginWindowPID" >> "$logFile"
                    sudo kill -9 "$loginWindowPID"
                    sleep 5
                    echo "$timestamp - BREAK LOOP" >> "$logFile"
                    break
            else
                    timestamp=$(date)
                    loginWindowPID=$(pgrep loginwindow)
                    echo "$timestamp - PROCESS NUMBER: $loginWindowPID" >> "$logFile"
            fi
            sleep 2
            echo "$(date) - END LOOP" >> "$logFile"
    done
    sleep 5
    newloginWindowPID=$(pgrep loginwindow)
    uend=$(date -j -f "%a %b %d %T %Z %Y" "date" "+%s")
    echo "$(date) - fixDuration: $((uend - ustart)) seconds" >> "$logFile"
    echo "$(date) - oldLoginWindowPID #: $loginWindowPID" >> "$logFile"
    echo "$(date) - newLoginWindowPID #: $newloginWindowPID" >> "$logFile"
    echo "------------BOOT COMPLETE $(date)----------" >> "$logFile"

Save out the file (Ctrl+O + [ENTER]) and exit nano (Ctrl+X + [ENTER])

  1. Make script executable and change ownership to root:wheel

    sudo chmod +x /usr/local/bin/fixHang.sh
    sudo chown root:wheel /usr/local/bin/fixHang.sh
    
  2. Create a launch daemon in /Library/LaunchDaemons which when loaded will execute the fixHang.sh script on startup

    sudo touch /Library/LaunchDaemons/com.startup.fixhang.plist
    sudo nano /Library/LaunchDaemons/com.startup.fixhang.plist
    
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
        <key>Label</key>
        <string>com.startup.fixhang</string>
        <key>LaunchOnlyOnce</key>
        <true/>
        <key>LimitLoadToSessionType</key>
        <array>
            <string>Aqua</string>
        </array>
        <key>ProgramArguments</key>
        <array>
            <string>sh</string>
            <string>-c</string>
            <string>/usr/local/bin/fixHang.sh</string>
        </array>
        <key>RunAtLoad</key>
        <true/>
    </dict>
    </plist>
    

Save out the file (Ctrl+O + ENTER) and exit nano (Ctrl+X + ENTER)

  1. Change ownership of /Library/LaunchDaemons/com.startup.fixhang.plist to root:wheel

    sudo chown root:wheel /Library/LaunchDaemons/com.startup.fixhang.plist
    
  2. Load the launch daemon for execution at startup

    sudo launchctl load /Library/LaunchDaemons/com.startup.fixhang.plist