microsoft / WSL

Issues found on WSL
https://docs.microsoft.com/windows/wsl
MIT License
17.25k stars 812 forks source link

Python WSL read failed 5: I/O error #5590

Closed JuanPabloMF closed 7 months ago

JuanPabloMF commented 4 years ago

Environment

Windows build number: Microsoft Windows [Version 10.0.19041.330]
Your Distribution version: Ubuntu Release 18.04
Whether the issue is on WSL 2 and/or WSL 1: 2

Steps to reproduce

I am calling python file1.py and getting the error "read failed 5: I/O error" multiple times.

Here is the file1.py code

import subprocess

sc_win_path = "C:\\Program Files (x86)\\StarCraft\\x86\\StarCraft.exe"
keys_repo_win_path = "C:\\Users\\juanpablo\\Documents\\open_sc_replay\\openrep.py"

run_cmd = ["cmd.exe", "/C"]
open_sc_cmd = run_cmd + [sc_win_path, "-launch"]
execute_keys_cmd = run_cmd + ["python", keys_repo_win_path]
close_app_cmd = run_cmd + ['taskkill','/f', '/im']

task_names = {
    'bnet': 'Battle.net.exe',
    'starcraft': 'StarCraft.exe',
    }

def open_rep():
    subprocess.Popen(open_sc_cmd)
    #subprocess.Popen(execute_keys_cmd)

def close_app(task):
    subprocess.Popen(close_app_cmd + [task_names[task]])

open_rep()

Basically this file opens the game and executes a few key strokes in order to open automatically a replay.

Openrep.py contains the following code:

import pyautogui
import keys
from keys import PressKey
import time
import math

def chain_keys(keys_list):
    for t, key in keys_list:
        time.sleep(t)
        PressKey(getattr(keys, key))
        print(key)

if __name__ == "__main__":
    rep_speed = 4
    time.sleep(14)
    goto_playcustom_seq = zip([1.5]*4,['S','E', 'O', 'U'])
    chain_keys(goto_playcustom_seq)
    chain_keys([(2,'Enter')])
    time.sleep(2)   
    for _ in range(int(math.log(rep_speed,2))+1): 
        time.sleep(1)
        pyautogui.press('U')

The keys file contains the following:

# direct inputs
# source to this solution and code:
# http://stackoverflow.com/questions/14489013/simulate-python-keypresses-for-controlling-a-game
# http://www.gamespp.com/directx/directInputKeyboardScanCodes.html

import ctypes
import time

SendInput = ctypes.windll.user32.SendInput

E = 0x12
Enter = 0x1C
W = 0x11
A = 0x1E
S = 0x1F
D = 0x20
U = 0x16
O = 0x18
up = 0x48
down = 0x50

# C struct redefinitions 
PUL = ctypes.POINTER(ctypes.c_ulong)
class KeyBdInput(ctypes.Structure):
    _fields_ = [("wVk", ctypes.c_ushort),
                ("wScan", ctypes.c_ushort),
                ("dwFlags", ctypes.c_ulong),
                ("time", ctypes.c_ulong),
                ("dwExtraInfo", PUL)]

class HardwareInput(ctypes.Structure):
    _fields_ = [("uMsg", ctypes.c_ulong),
                ("wParamL", ctypes.c_short),
                ("wParamH", ctypes.c_ushort)]

class MouseInput(ctypes.Structure):
    _fields_ = [("dx", ctypes.c_long),
                ("dy", ctypes.c_long),
                ("mouseData", ctypes.c_ulong),
                ("dwFlags", ctypes.c_ulong),
                ("time",ctypes.c_ulong),
                ("dwExtraInfo", PUL)]

class Input_I(ctypes.Union):
    _fields_ = [("ki", KeyBdInput),
                 ("mi", MouseInput),
                 ("hi", HardwareInput)]

class Input(ctypes.Structure):
    _fields_ = [("type", ctypes.c_ulong),
                ("ii", Input_I)]

# Actuals Functions

def PressKey(hexKeyCode):
    extra = ctypes.c_ulong(0)
    ii_ = Input_I()
    ii_.ki = KeyBdInput( 0, hexKeyCode, 0x0008, 0, ctypes.pointer(extra) )
    x = Input( ctypes.c_ulong(1), ii_ )
    ctypes.windll.user32.SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))

def ReleaseKey(hexKeyCode):
    extra = ctypes.c_ulong(0)
    ii_ = Input_I()
    ii_.ki = KeyBdInput( 0, hexKeyCode, 0x0008 | 0x0002, 0, ctypes.pointer(extra) )
    x = Input( ctypes.c_ulong(1), ii_ )
    ctypes.windll.user32.SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))

if __name__ == '__main__':
    PressKey(0x11)
    time.sleep(1)
    ReleaseKey(0x11)
    time.sleep(1) 

Expected behavior

Calling for python file1.py should open the game and execute the keystrokes. This works fine if I call directly from powershell or cmd the two subprocess commands. Also it works fine if I open a python shell in WSL and manually import the module and execute the function.

Actual behavior

I am repeateadly getting "read failed 5: I/O error". I did a wsl --shutdown which made it work for a while, but then the error started repeating.

2020-07-15 (2)

JuanPabloMF commented 4 years ago

os.popen works whilst subprocess.popen gives read failed error. Looks like with subprocess.popen the windows shell settings are not loaded.

ctataryn commented 4 years ago

While not python related, ever since upgrading to WSL2 from WSL1 I randomly get these errors while typing in Windows Terminal. For instance, here I was typing ls -al:

image

ctataryn commented 4 years ago

This is rendering my WSL terminal useless as it is happening quite often and the only solution I can find is to exit Windows Terminal and startup another one until it happens again.

Is there any sort of diagnostic information I can provide during the times in which this error occurrences which would help someone figure out its root cause? Again, this only started happening with WSL2.

ctataryn commented 4 years ago

Just by luck today I happened to find the root cause of the problems for me. I use gvim for Windows to edit files on the WSL filesystem. I do this via the \\wsl$ fileshare using this script:

~/bin/gvim:

#!/bin/bash
CMNT='/c'
CMD='/c/Windows/System32/cmd.exe'
GVIM='/c/Program Files (x86)/Vim/vim81/gvim.exe'
FILE=`realpath "${1:-.}"`
if [[ $FILE == $CMNT/* ]] ;
then
  FILE=${FILE/$CMNT\//C:\\}
else
  # replace the first forward slash
  FILE=${FILE/\//\\\\wsl\$\\Ubuntu\\}
fi
# replace the rest
FILE=${FILE//\//\\}
echo Launch gvim for file: $FILE
`"$GVIM" $FILE` &

This allows me to type: gvim myfile and have it do the necessary conversion of the path from WSL to Windows for myfile.txt. For instance:

$ pwd
/home/craiger/tmp
$ gvim myfile.txt

This would launch gvim for Windows in the following way:

/c/Program Files (x86)/Vim/vim81/gvim.exe \\wsl$\Ubuntu\home\craiger\tmp\myfile.txt &

If I was in a /c folder (Windows filesystem) then it'd open C:\...\myfile.txt instead.

So long as that instance of gvim is running, I will get read failed 5: I/O error for each character I type in the terminal as long as gvim remains open. As soon as I close gvim, the errors go away.

Is there something I can do to maintain my ability to use gvim to open files within the WSL filesystem but get rid of the error I'm receiving in the terminal as a result?

ctataryn commented 4 years ago

I think what I'll do is open this as a separate ticket as I don't believe it is Python related

microsoft-github-policy-service[bot] commented 7 months ago

This issue has been automatically closed since it has not had any activity for the past year. If you're still experiencing this issue please re-file this as a new issue or feature request.

Thank you!