forked from micropython/micropython
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Closed
Description
From #10615 (comment):
The PR seems like a rational fix, so maybe completely unrelated, but under atypically extreme duress (hammering on TCP socket, and hammering on interrupts ...assuming the code is doing what I think), a TCP client will get hardfaults somewhat regularly with PR artifacts on Pico W:
Client code (on a Pico W):
# Adafruit CircuitPython 10.0.0-beta.3 on 2025-08-29; Raspberry Pi Pico W with rp2040 # Adafruit CircuitPython 10.0.0-beta.3-8-g9e7a03cbc2 on 2025-09-05; Raspberry Pi Pico W with rp2040 # "Hard fault: memory access or instruction error." (after "Connecting") import time import supervisor import microcontroller import os import random import traceback import wifi import socketpool import array import pulseio import board # edit host and port to match server HOST = "192.168.6.57" PORT = 5000 TIMEOUT = 1 INTERVAL = 0.1 MAXBUF = 8192 def send_pulses(): # on off on ... MAX_TRAIN = 17 for p_out in range(1, len(pulse_outs)): p_train = [] for p_item in range(0, random.randint(3, MAX_TRAIN)): p_train.append(random.randint(100, 10_000)) pulses = array.array('H', p_train) pulse_outs[p_out].send(pulses) time.sleep(3) # wait for serial after reset print("Connecting to Wifi") while not wifi.radio.connected: try: wifi.radio.connect(os.getenv('WIFI_SSID'), os.getenv('WIFI_PASSWORD')) except Exception as ex: traceback.print_exception(ex, ex, ex.__traceback__) time.sleep(1 + random.random()) supervisor.reload() # microcontroller.reset() pool = socketpool.SocketPool(wifi.radio) print(wifi.radio.ipv4_address) # 50% duty cycle at 38kHz. pulse_outs = [] pulse_outs.append(pulseio.PulseOut(board.GP0, frequency=38000, duty_cycle=32768)) pulse_outs.append(pulseio.PulseOut(board.GP1, frequency=38000, duty_cycle=32768)) pulse_outs.append(pulseio.PulseOut(board.GP2, frequency=38000, duty_cycle=32768)) pulse_outs.append(pulseio.PulseOut(board.GP3, frequency=38000, duty_cycle=32768)) buf = bytearray(MAXBUF) while True: try: print("Create TCP Client Socket") with pool.socket(pool.AF_INET, pool.SOCK_STREAM) as s: s.settimeout(TIMEOUT) print("Connecting") s.connect((HOST, PORT)) payload = bytearray() for _ in range(random.randint(0, MAXBUF)): payload.append(random.choice((b'0123456789ABCDEF'))) send_pulses() ##### size = s.send(payload) print("Sent", size, "bytes") send_pulses() ##### size = s.recv_into(buf) # occasionally on recv_into: # OSError: [Errno 104] ECONNRESET # OSError: [Errno 9] EBADF # OSError: [Errno 116] ETIMEDOUT print('Received', size, "bytes", buf[:size]) except Exception as ex: print(f"⚠️", end=" ") traceback.print_exception(ex, ex, ex.__traceback__) time.sleep(INTERVAL)With beta.3, hardfaults occur under less duress than above, but I hadn't actually replicated it with the prior testing in the previous comment, so just wanted to see how it could be triggered.Server code (on a Pico 2W):
import time import microcontroller import os import random import traceback import wifi import socketpool HOST = "" PORT = 5000 TIMEOUT = None BACKLOG = 2 MAXBUF = 8192 time.sleep(3) # wait for serial after reset print("Connecting to Wifi") while not wifi.radio.connected: try: wifi.radio.connect(os.getenv('WIFI_SSID'), os.getenv('WIFI_PASSWORD')) except Exception as ex: traceback.print_exception(ex, ex, ex.__traceback__) time.sleep(1) microcontroller.reset() pool = socketpool.SocketPool(wifi.radio) print(wifi.radio.ipv4_address) print("Create TCP Server socket", (HOST, PORT)) with pool.socket(pool.AF_INET, pool.SOCK_STREAM) as s: s.setsockopt(pool.SOL_SOCKET, pool.SO_REUSEADDR, 1) # s.settimeout(TIMEOUT) s.bind((HOST, PORT)) s.listen(BACKLOG) print("Listening") buf = bytearray(MAXBUF) while True: try: print("Accepting connections") conn, addr = s.accept() conn.settimeout(TIMEOUT) print("Accepted from", addr) size = conn.recv_into(buf, MAXBUF) print("Received", buf[:size], size, "bytes") conn.send(buf[:size]) print("Sent", buf[:size], size, "bytes") except Exception as ex: print(f"⚠️", end=" ") traceback.print_exception(ex, ex, ex.__traceback__) finally: time.sleep(0.1) # too short and client gets "OSError: [Errno 104] ECONNRESET" in recv conn.close()There also seems to be a situation where the server closing the connection immediately after sending the response can cause
OSError: [Errno 104] ECONNRESETat the client (somehow before the client has read all of the incoming packet... some buffering issue?).Originally posted by @anecdata in #10615 (comment)