Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Segfault if ipc requests sent too rapidly #45

Open
2e0byo opened this issue Feb 24, 2023 · 7 comments
Open

Segfault if ipc requests sent too rapidly #45

2e0byo opened this issue Feb 24, 2023 · 7 comments

Comments

@2e0byo
Copy link
Contributor

2e0byo commented Feb 24, 2023

If I send ipc requests too rapidly, hyprpaper segfaults in a variety of places (curiously, often in vnsprint), or gets a bus error.

I have a script to load a random wallpaper:

#!/usr/bin/python
from pathlib import Path
from random import choices
from subprocess import run

cmdbase = ["hyprctl", "hyprpaper"]

def load_backgrounds(mapping: dict[str, Path]):
    mapping: dict[str, str] = {k: str(v) for k, v in mapping.items()}
    for bg in mapping.values():
        run(cmdbase + ["preload", bg])
    for monitor, bg in mapping.items():
        run(cmdbase + ["wallpaper", f"{monitor},{bg}"])
    run(cmdbase + ["unload", "all"])


if __name__ == "__main__":
    imgs = Path("~/google-drive/Desktop Backgrounds").expanduser().resolve()
    monitors = {"DP-1", "DP-2"}
    extns = {".jpg", ".jpeg", ".png"}
    available = [x for x in imgs.glob("*") if x.suffix.lower() in extns]
    backgrounds = dict(zip(monitors, choices(available, k=len(monitors))))
    load_backgrounds(backgrounds)

If I run this in a loop at the terminal it will segfault after ~3 iterations. If I add a sleep, i.e.

while true; do
    random_wallpaper.py
    sleep 0.5

I can control the behaviour somewhat. With 0.5 it dies only occasionally, and usually with sigbus. With 0.1 it segfaults pretty quickly. Obviously looping over wallpapers isn't very useful, but I can't guarantee that a user won't hit the 'reload' button in quick succession.

For the time being I can work around it with a file lock. Should the socket code block until the load operation is finished?

version

Latest master with my case-insensitive patch, i.e. 0a85097

@2e0byo 2e0byo changed the title Segfault if switch too rapidly Segfault if ipc requests sent too rapidly Feb 24, 2023
@lenianiva
Copy link

lenianiva commented May 8, 2023

Is there a temporary workaround to this problem? I switch wallpapers pretty frequently since I have a different one for each workspace, and hyprpaper would crash a couple times a day.

@vaxerski
Copy link
Member

vaxerski commented May 8, 2023

try with 3596630

@2e0byo
Copy link
Contributor Author

2e0byo commented May 9, 2023

Now we die normally:

zwlr_layer_surface_v1@24: error 0: wrong configure serial: 425141
[Thread 0x7ffff6a706c0 (LWP 2092053) exited]
[Inferior 1 (process 2092049) exited normally]

The particular serial changes so it could be memory corruption. If you tell me what to set a breakpoint on I'll see if I can get a proper backtrace.

This was a segfault before and I couldn't reproduce this time, so I think the segfault is cured, even if the problem has just moved.

@2e0byo
Copy link
Contributor Author

2e0byo commented May 9, 2023

Is there a temporary workaround to this problem? I switch wallpapers pretty frequently since I have a different one for each workspace, and hyprpaper would crash a couple times a day.

You can set it up to restart e.g. with systemd. I think there's an example in the linked issue. OTOH I don't have any noticeable crashes with the script above ticking every 5 minutes after adding a delay and a lock:

from time import sleep

from filelock import FileLock
lock = FileLock("/tmp/hyprpaper.lock")


def load_backgrounds(mapping: dict[str, Path]):
    with lock:
       # as above
        sleep(0.5)

No need to use python if you don't want to, this is trivial in e.g. bash. Using a file lock might be the trick if you're flipping between workspaces fast enough to get there before hyprpaper has settled down from the last switch.

@lenianiva
Copy link

lenianiva commented Sep 20, 2023

Now we die normally:

zwlr_layer_surface_v1@24: error 0: wrong configure serial: 425141
[Thread 0x7ffff6a706c0 (LWP 2092053) exited]
[Inferior 1 (process 2092049) exited normally]

The particular serial changes so it could be memory corruption. If you tell me what to set a breakpoint on I'll see if I can get a proper backtrace.

This was a segfault before and I couldn't reproduce this time, so I think the segfault is cured, even if the problem has just moved.

I think there's a race condition here:

[Event] Configuring with serial 659167
[Event] Configuring with serial 659167 done
[LOG] configure for DP-1
Configuring with serial 659167
Configuring with serial 659167 finished
[LOG] Image data for DP-1: /home/aniva/.config/hypr/wallpapers/7.jpg at [-0.00, 0.00], scale: 1.00 (original image size: [3840, 2160])
[LOG] Submitting viewport dest size 3840x2160 for 60000d20
[Event] Configuring with serial 659171
[Event] Configuring with serial 659171 done
[LOG] configure for DP-1
[LOG] handlePreferredScale: 1.00 for 7f3e60000d20
[LOG] handlePreferredScale: 1.00 for 7f3e60000d20
Configuring with serial 659171
Configuring with serial 659171 finished
[LOG] Image data for DP-1: /home/aniva/.config/hypr/wallpapers/7.jpg at [-0.00, 0.00], scale: 1.00 (original image size: [3840, 2160])
[LOG] Submitting viewport dest size 3840x2160 for 60000d20
zwlr_layer_surface_v1@41: error 0: wrong configure serial: 659167

The [Event] messages are sent from the event handler and the Configure with serial ... messages are sent from CHyprpaper::recheckMonitor. It seems like the ack_configure event for 167 has not reached the client when the event for 171 is received by hyprpaper.

I'm not sure how can we solve this. Even setting the configuration serial as atomic doesn't mitigate this problem.

@ssvx
Copy link

ssvx commented Mar 5, 2024

Arrived here via search for the issue after i experienced it by accidentally hitting the [1] key when switching to workspace 2 by pressing [Super]+[2].

So by following the Hyprland wiki to set up different wallpapers for each workspace and then cycle them too fast: crash.

The claim "Hyprpaper is a blazing fast wallpaper utility" seems a bit weird given that this issue happens when you "switch too fast" ... 😅

Right now i use a script to subscribe to the Hyprland socket and only switch the wallpapers after a timeout during which no workspace change happens. It works but doesn't feel "blazing fast" tbf.

//edit:
After reducing the DelaySec to 0.1 it feels relatively fast (enough)... so taking the chance to be laughed at, here's my script...

#!/bin/bash

# Script vars (no touch)
ScriptDir=$(dirname "$0")
TimerPid=0

# Config vars (do touch)
DelaySec=0.1
JsonFile="$ScriptDir/wallpapers.json"
CurFile="/tmp/wallpaperd"

# Save current terminal settings
SttyBackup=$(stty -g)
# Disable echoing of control characters (^C)
stty -echoctl

hyprctl hyprpaper unload all


# Load Wallpapers associative array from the JSON file
declare -A Wallpapers
FirstPaper=""
while IFS="=" read -r key value; do
	if [[ $FirstPaper == "" ]]; then
		FirstPaper=$value
	fi
	Wallpapers["$key"]="$value"
	echo "preloading $value"
	hyprctl hyprpaper preload "$value"
done < <(jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]" $JsonFile)

WorkspaceName=$(hyprctl -j activeworkspace | jq -r '.name')
echo "Current workspace '$WorkspaceName'"
WallpaperValue="${Wallpapers[$WorkspaceName]}"
if [[ -z $WallpaperValue ]]; then
	WallpaperValue="$FirstPaper"
fi
hyprctl hyprpaper wallpaper "DP-2,$WallpaperValue"
echo "$WallpaperValue" > "$CurFile"

# Handle termination / ctrl+c
CleanUp () {
	echo "Cleaning up..."
	if [ -f "$CurFile" ]; then
		rm $CurFile
	fi
	stty "$SttyBackup"
	exit 0
}

# Use trap to call CleanUp when a SIGINT is received
trap CleanUp SIGINT SIGTERM

# Function to change wallpaper
WallpaperSet () {
	local CurrentPaper=""
	local WorkspaceName="$1"
	local WallpaperValue="${Wallpapers[$WorkspaceName]}"
	if [ -f "$CurFile" ]; then
		CurrentPaper=$(< "$CurFile")
		echo "CurrentPaper is $CurrentPaper"
	fi

	if [[ -n "$WallpaperValue" && $WallpaperValue != $CurrentPaper ]]; then
		echo "Set wallpaper '$WallpaperValue'"
		echo "$WallpaperValue" > "$CurFile"
		# Use hyprctl to change the wallpaper
		hyprctl hyprpaper wallpaper "DP-2,$WallpaperValue"
	else
		echo "Same wallpaper, skipping..."
	fi
}

WallpaperCue () {
	local WorkspaceName="$1"
	[[ 0 < $TimerPid ]] && kill -0 $TimerPid > /dev/null 2>&1 && kill "$TimerPid"
	(sleep $DelaySec; WallpaperSet "$WorkspaceName") &
	TimerPid=$!
}

# Subscribe to Hyprland socket and process the stream
socat -u UNIX-CONNECT:/tmp/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock - | while read -r line; do
	#echo $line
	if [[ "$line" == "activespecial>>special:"* ]]; then
		SpecialWorkspace="${line#activespecial>>}"  # Removes everything up to and including ">>"
		SpecialWorkspace="${SpecialWorkspace%%,*}"  # Removes everything after and including ","
		echo "Special workspace name '$SpecialWorkspace'"
		WallpaperCue "$SpecialWorkspace"
	fi
	if [[ "$line" == "activespecial>>,"* ]]; then
		echo "Reset special workspace to '$WorkspaceName'"
		WallpaperCue "$WorkspaceName"
	fi
	if [[ "$line" == "workspace>>"* ]]; then
		WorkspaceName="${line#workspace>>}"
		echo "Workspace name '$WorkspaceName'"

		# Check if the workspace name exists in the Wallpapers array
		if [[ -n "${Wallpapers[$WorkspaceName]}" ]]; then
			WallpaperCue "$WorkspaceName"
		fi
	fi
done

For configuration it expects a wallpapers.json in the same directory (see config vars) in this format:

{
	"1": "~/Pictures/Wallpaper/something.png",
	"2": "~/Pictures/Wallpaper/somethingelse.webp",
	"special:magic": "~/Pictures/Wallpaper/whatever.jpg"
}

Replace the array keys with your workspace names.. special workplaces work too..

//edit2:
I also tried to use hyprctl hyprpaper listactive for initialisation but it only says "invalid command". Not sure if i'm stupid or if it's bugged or if my version (hyprpaper 0.6.0-3) just doesn't feature it yet.

@lenianiva
Copy link

Has the issue been fixed? I recently updated my hyprpaper to 0.7.0 and rapid switching no longer crashes it.

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

No branches or pull requests

4 participants