5252#include "supervisor/memory.h"
5353#include "supervisor/port.h"
5454#include "supervisor/serial.h"
55- #include "supervisor/shared/autoreload .h"
55+ #include "supervisor/shared/reload .h"
5656#include "supervisor/shared/safe_mode.h"
5757#include "supervisor/shared/stack.h"
5858#include "supervisor/shared/status_leds.h"
@@ -124,7 +124,6 @@ static void reset_devices(void) {
124124}
125125
126126STATIC void start_mp (supervisor_allocation * heap , bool first_run ) {
127- autoreload_stop ();
128127 supervisor_workflow_reset ();
129128
130129 // Stack limit should be less than real stack size, so we have a chance
@@ -329,14 +328,20 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
329328 result .exception = MP_OBJ_NULL ;
330329 result .exception_line = 0 ;
331330
332- bool skip_repl ;
331+ bool skip_repl = false ;
333332 bool skip_wait = false;
334333 bool found_main = false;
335334 uint8_t next_code_options = 0 ;
336335 // Collects stickiness bits that apply in the current situation.
337336 uint8_t next_code_stickiness_situation = SUPERVISOR_NEXT_CODE_OPT_NEWLY_SET ;
338337
338+ // Do the filesystem flush check before reload in case another write comes
339+ // in while we're doing the flush.
339340 if (safe_mode == NO_SAFE_MODE ) {
341+ stack_resize ();
342+ filesystem_flush ();
343+ }
344+ if (safe_mode == NO_SAFE_MODE && !autoreload_pending ()) {
340345 static const char * const supported_filenames [] = STRING_LIST (
341346 "code.txt" , "code.py" , "main.py" , "main.txt" );
342347 #if CIRCUITPY_FULL_BUILD
@@ -345,8 +350,6 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
345350 "main.txt.py" , "main.py.txt" , "main.txt.txt" ,"main.py.py" );
346351 #endif
347352
348- stack_resize ();
349- filesystem_flush ();
350353 supervisor_allocation * heap = allocate_remaining_memory ();
351354
352355 // Prepare the VM state. Includes an alarm check/reset for sleep.
@@ -389,13 +392,14 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
389392
390393 // Print done before resetting everything so that we get the message over
391394 // BLE before it is reset and we have a delay before reconnect.
392- if (reload_requested && result . return_code == PYEXEC_EXCEPTION ) {
393- serial_write_compressed (translate ("\nCode stopped by auto-reload.\n" ));
395+ if (( result . return_code & PYEXEC_RELOAD ) && supervisor_get_run_reason () == RUN_REASON_AUTO_RELOAD ) {
396+ serial_write_compressed (translate ("\nCode stopped by auto-reload. Reloading soon. \n" ));
394397 } else {
395398 serial_write_compressed (translate ("\nCode done running.\n" ));
396399 }
397400
398- // Finished executing python code. Cleanup includes a board reset.
401+
402+ // Finished executing python code. Cleanup includes filesystem flush and a board reset.
399403 cleanup_after_vm (heap , result .exception );
400404
401405 // If a new next code file was set, that is a reason to keep it (obviously). Stuff this into
@@ -407,8 +411,14 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
407411 next_code_options |= SUPERVISOR_NEXT_CODE_OPT_NEWLY_SET ;
408412 }
409413
410- if (reload_requested ) {
414+ if (result . return_code & PYEXEC_RELOAD ) {
411415 next_code_stickiness_situation |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_RELOAD ;
416+ // Reload immediately unless the reload is due to autoreload. In that
417+ // case, we wait below to see if any other writes occur.
418+ if (supervisor_get_run_reason () != RUN_REASON_AUTO_RELOAD ) {
419+ skip_repl = true;
420+ skip_wait = true;
421+ }
412422 } else if (result .return_code == 0 ) {
413423 next_code_stickiness_situation |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_SUCCESS ;
414424 if (next_code_options & SUPERVISOR_NEXT_CODE_OPT_RELOAD_ON_SUCCESS ) {
@@ -426,7 +436,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
426436 }
427437 }
428438 if (result .return_code & PYEXEC_FORCED_EXIT ) {
429- skip_repl = reload_requested ;
439+ skip_repl = false ;
430440 skip_wait = true;
431441 }
432442 }
@@ -466,22 +476,27 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
466476 size_t total_time = blink_time + LED_SLEEP_TIME_MS ;
467477 #endif
468478
479+ // This loop is waits after code completes. It waits for fake sleeps to
480+ // finish, user input or autoreloads.
469481 #if CIRCUITPY_ALARM
470482 bool fake_sleeping = false;
471483 #endif
472484 while (!skip_wait ) {
473485 RUN_BACKGROUND_TASKS ;
474486
475- // If a reload was requested by the supervisor or autoreload, return
476- if (reload_requested ) {
487+ // If a reload was requested by the supervisor or autoreload, return.
488+ if (autoreload_ready () ) {
477489 next_code_stickiness_situation |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_RELOAD ;
478490 // Should the STICKY_ON_SUCCESS and STICKY_ON_ERROR bits be cleared in
479491 // next_code_stickiness_situation? I can see arguments either way, but I'm deciding
480492 // "no" for now, mainly because it's a bit less code. At this point, we have both a
481493 // success or error and a reload, so let's have both of the respective options take
482494 // effect (in OR combination).
483- reload_requested = false;
484495 skip_repl = true;
496+ // We're kicking off the autoreload process so reset now. If any
497+ // other reloads trigger after this, then we'll want another wait
498+ // period.
499+ autoreload_reset ();
485500 break ;
486501 }
487502
@@ -508,7 +523,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
508523 #endif
509524
510525 // If messages haven't been printed yet, print them
511- if (!printed_press_any_key && serial_connected ()) {
526+ if (!printed_press_any_key && serial_connected () && ! autoreload_pending () ) {
512527 if (!serial_connected_at_start ) {
513528 print_code_py_status_message (safe_mode );
514529 }
@@ -627,13 +642,14 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
627642 }
628643 }
629644
645+ // Done waiting, start the board back up.
646+
630647 // free code allocation if unused
631648 if ((next_code_options & next_code_stickiness_situation ) == 0 ) {
632649 free_memory (next_code_allocation );
633650 next_code_allocation = NULL ;
634651 }
635652
636- // Done waiting, start the board back up.
637653 #if CIRCUITPY_STATUS_LED
638654 if (led_active ) {
639655 new_status_color (BLACK );
@@ -757,7 +773,7 @@ STATIC int run_repl(bool first_run) {
757773 usb_setup_with_vm ();
758774 #endif
759775
760- autoreload_suspend (AUTORELOAD_LOCK_REPL );
776+ autoreload_suspend (AUTORELOAD_SUSPEND_REPL );
761777
762778 // Set the status LED to the REPL color before running the REPL. For
763779 // NeoPixels and DotStars this will be sticky but for PWM or single LED it
@@ -787,7 +803,7 @@ STATIC int run_repl(bool first_run) {
787803 status_led_deinit ();
788804 #endif
789805
790- autoreload_resume (AUTORELOAD_LOCK_REPL );
806+ autoreload_resume (AUTORELOAD_SUSPEND_REPL );
791807 return exit_code ;
792808}
793809
0 commit comments