Skip to content

Commit 1a28af6

Browse files
committed
Merge branch 'main' into feature/distributed-erlang
2 parents 44191fc + a00098a commit 1a28af6

File tree

10 files changed

+107
-37
lines changed

10 files changed

+107
-37
lines changed

.github/workflows/build-and-test.yaml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,60 +367,69 @@ jobs:
367367
timeout-minutes: 15
368368
working-directory: build
369369
run: |
370+
ulimit -c unlimited
370371
./tests/test-erlang -s prime_smp
371372
valgrind ./tests/test-erlang -s prime_smp
372373
373374
- name: "Test: test-enif"
374375
working-directory: build
375376
run: |
377+
ulimit -c unlimited
376378
./tests/test-enif
377379
valgrind ./tests/test-enif
378380
379381
- name: "Test: test-mailbox"
380382
working-directory: build
381383
run: |
384+
ulimit -c unlimited
382385
./tests/test-mailbox
383386
valgrind ./tests/test-mailbox
384387
385388
- name: "Test: test-structs"
386389
timeout-minutes: 10
387390
working-directory: build
388391
run: |
392+
ulimit -c unlimited
389393
./tests/test-structs
390394
valgrind ./tests/test-structs
391395
392396
- name: "Test: test_etest.avm"
393397
timeout-minutes: 5
394398
working-directory: build
395399
run: |
400+
ulimit -c unlimited
396401
./src/AtomVM ./tests/libs/etest/test_etest.avm
397402
valgrind ./src/AtomVM ./tests/libs/etest/test_etest.avm
398403
399404
- name: "Test: test_estdlib.avm"
400405
timeout-minutes: 5
401406
working-directory: build
402407
run: |
408+
ulimit -c unlimited
403409
./src/AtomVM ./tests/libs/estdlib/test_estdlib.avm
404410
valgrind ./src/AtomVM ./tests/libs/estdlib/test_estdlib.avm
405411
406412
- name: "Test: test_eavmlib.avm"
407413
timeout-minutes: 10
408414
working-directory: build
409415
run: |
416+
ulimit -c unlimited
410417
./src/AtomVM ./tests/libs/eavmlib/test_eavmlib.avm
411418
valgrind ./src/AtomVM ./tests/libs/eavmlib/test_eavmlib.avm
412419
413420
- name: "Test: test_alisp.avm"
414421
timeout-minutes: 10
415422
working-directory: build
416423
run: |
424+
ulimit -c unlimited
417425
./src/AtomVM ./tests/libs/alisp/test_alisp.avm
418426
valgrind ./src/AtomVM ./tests/libs/alisp/test_alisp.avm
419427
420428
- name: "Test: Tests.avm (Elixir)"
421429
timeout-minutes: 10
422430
working-directory: build
423431
run: |
432+
ulimit -c unlimited
424433
if command -v elixirc &> /dev/null
425434
then
426435
./src/AtomVM ./tests/libs/exavmlib/Tests.avm
@@ -430,7 +439,40 @@ jobs:
430439
- name: "Install and smoke test"
431440
working-directory: build
432441
run: |
442+
ulimit -c unlimited
433443
sudo PATH=${PATH} make install
434444
atomvm examples/erlang/hello_world.avm
435445
atomvm -v
436446
atomvm -h
447+
448+
- name: "Run coredumpctl info"
449+
if: ${{ failure() }}
450+
run: |
451+
# Wait until systemd-coredump finished
452+
while ps x | grep -cE 'systemd-[c]oredump'; do
453+
echo systemd-coredump is still running
454+
sleep 1
455+
done
456+
# info works on all versions of ubuntu
457+
coredumpctl info || true
458+
# The following only works on recent versions of ubuntu
459+
coredumpctl debug --debugger-arguments="-batch -ex 'info all-registers'" || true
460+
coredumpctl debug --debugger-arguments="-batch -ex 'info threads'" || true
461+
coredumpctl debug --debugger-arguments="-batch -ex 'thread apply all bt full'" || true
462+
coredumpctl debug --debugger-arguments='-batch -ex "display /10i $pc"' || true
463+
coredumpctl dump -o core.dump || true
464+
if [ -e core.dump ]; then
465+
mkdir core
466+
mv core.dump core/
467+
cp build/src/AtomVM core/
468+
cp build/tests/test-* core/
469+
fi
470+
471+
- name: "Upload any dumped core"
472+
uses: actions/upload-artifact@v4
473+
if: ${{ failure() }}
474+
with:
475+
name: core-${{ matrix.os }}-${{ matrix.cc }}-${{ matrix.otp }}-${{ github.run_id }}-${{ github.run_attempt }}
476+
path: |
477+
core/*
478+
retention-days: 5

.github/workflows/esp32-mkimage.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ jobs:
4545
elixir_version: ["1.17"]
4646
rebar3_version: ["3.24.0"]
4747
compiler_pkgs: ["clang-14"]
48-
soc: ["esp32", "esp32c2", "esp32c3", "esp32s2", "esp32s3", "esp32c6", "esp32h2"]
48+
soc: ["esp32", "esp32c2", "esp32c3", "esp32s2", "esp32s3", "esp32c6", "esp32h2", "esp32p4"]
4949
flavor: ["", "-elixir"]
5050

5151
env:

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3333

3434
- ESP32: improved sntp sync speed from a cold boot.
3535
- Fixed `gen_server` internal messages to match OTP so it works across erlang distribution
36+
- Utilize reserved `phy_init` partition on ESP32 to store wifi calibration for faster connections.
3637

3738
## [0.6.6] - Unreleased
3839

3940
### Added
4041

4142
- Added the ability to run beams from the CLI for Generic Unix platform (it was already possible with nodejs and emscripten).
4243
- Added support for 'erlang:--/2'.
44+
- Added preliminary support for ESP32P4 (no networking support yet).
4345

4446
### Fixed
4547

@@ -61,6 +63,7 @@ certain VM instructions are used.
6163
- Fixed a race condition affecting multi-core MCUs where a timeout would not be properly cleared
6264
- Fixed a double free when esp32 uart driver was closed, yielding an assert abort
6365
- Fixed compilation with latest debian gcc-arm-none-eabi
66+
- Fix `network:stop/0` on ESP32 so the network can be started again
6467

6568
## [0.6.5] - 2024-10-15
6669

libs/estdlib/src/erlang.erl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ process_info(_Pid, _Key) ->
269269
%% <li><b>esp32_free_heap_size</b> the number of (noncontiguous) free bytes in the ESP32 heap (integer)</li>
270270
%% <li><b>esp32_largest_free_block</b> the number of the largest contiguous free bytes in the ESP32 heap (integer)</li>
271271
%% <li><b>esp32_minimum_free_size</b> the smallest number of free bytes in the ESP32 heap since boot (integer)</li>
272+
%% <li><b>esp32_chip_info</b> Details about the model and capabilities of the ESP32 device (map)</li>
272273
%% </ul>
273274
%%
274275
%% Additional keys may be supported on some platforms that are not documented here.

src/libAtomVM/globalcontext.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ COLD_FUNC void globalcontext_destroy(GlobalContext *glb)
234234
struct RefcBinary *refc = GET_LIST_ENTRY(item, struct RefcBinary, head);
235235
#ifndef NDEBUG
236236
if (refc->resource_type) {
237-
fprintf(stderr, "Warning, dangling resource of type %s, ref_count = %d\n", refc->resource_type->name, (int) refc->ref_count);
237+
fprintf(stderr, "Warning, dangling resource of type %s, ref_count = %d, data = %p\n", refc->resource_type->name, (int) refc->ref_count, refc->data);
238238
} else {
239239
fprintf(stderr, "Warning, dangling refc binary, ref_count = %d\n", (int) refc->ref_count);
240240
}

src/libAtomVM/otp_socket.c

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include <otp_socket.h>
3333
#include <port.h>
3434
#include <posix_nifs.h>
35+
#include <refc_binary.h>
3536
#include <scheduler.h>
3637
#include <smp.h>
3738
#include <sys.h>
@@ -286,6 +287,8 @@ static void socket_stop(ErlNifEnv *caller_env, void *obj, ErlNifEvent event, int
286287
if (rsrc_obj->selecting_process_id != INVALID_PROCESS_ID) {
287288
enif_demonitor_process(caller_env, rsrc_obj, &rsrc_obj->selecting_process_monitor);
288289
rsrc_obj->selecting_process_id = INVALID_PROCESS_ID;
290+
struct RefcBinary *rsrc_refc = refc_binary_from_data(rsrc_obj);
291+
refc_binary_decrement_refcount(rsrc_refc, caller_env->global);
289292
}
290293

291294
TRACE("socket_stop called on fd=%i\n", rsrc_obj->fd);
@@ -306,42 +309,43 @@ static void socket_down(ErlNifEnv *caller_env, void *obj, ErlNifPid *pid, ErlNif
306309
TRACE("socket_down called on process_id=%i\n", (int) *pid);
307310
#endif
308311

309-
// Increment the reference count so the resource doesn't go away
310-
// (enif_select will decrement the ref count)
311312
struct RefcBinary *rsrc_refc = refc_binary_from_data(rsrc_obj);
312-
refc_binary_increment_refcount(rsrc_refc);
313313
SMP_RWLOCK_WRLOCK(rsrc_obj->socket_lock);
314314

315-
#if OTP_SOCKET_BSD
316-
if (rsrc_obj->selecting_process_id != INVALID_PROCESS_ID) {
317-
// Monitor fired, so make sure we don't try to demonitor in select_stop
318-
// as it could crash trying to reacquire lock on process table
319-
rsrc_obj->selecting_process_id = INVALID_PROCESS_ID;
320-
enif_select(caller_env, rsrc_obj->fd, ERL_NIF_SELECT_STOP, rsrc_obj, NULL, term_nil());
315+
if (rsrc_obj->selecting_process_id == INVALID_PROCESS_ID) {
316+
SMP_RWLOCK_UNLOCK(rsrc_obj->socket_lock);
317+
return;
321318
}
319+
320+
#if OTP_SOCKET_BSD
321+
// Monitor fired, so make sure we don't try to demonitor in select_stop
322+
// as it could crash trying to reacquire lock on process table
323+
// enif_select can decrement ref count but it's at least 2 in this case (1 for monitor and 1 for select)
324+
rsrc_obj->selecting_process_id = INVALID_PROCESS_ID;
325+
enif_select(caller_env, rsrc_obj->fd, ERL_NIF_SELECT_STOP, rsrc_obj, NULL, term_nil());
322326
#elif OTP_SOCKET_LWIP
323327
// Monitor can be called when we're selecting, accepting or connecting.
324-
if (rsrc_obj->selecting_process_id != INVALID_PROCESS_ID) {
325-
LWIP_BEGIN();
326-
rsrc_obj->selecting_process_id = INVALID_PROCESS_ID;
327-
if (rsrc_obj->socket_state & SocketStateTCP) {
328-
if (rsrc_obj->socket_state & SocketStateTCPListening) {
329-
(void) tcp_close(rsrc_obj->tcp_pcb);
330-
} else {
331-
tcp_abort(rsrc_obj->tcp_pcb);
332-
}
333-
rsrc_obj->tcp_pcb = NULL;
334-
rsrc_obj->socket_state = SocketStateClosed;
335-
} else if (rsrc_obj->socket_state & SocketStateUDP) {
336-
udp_remove(rsrc_obj->udp_pcb);
337-
rsrc_obj->udp_pcb = NULL;
338-
rsrc_obj->socket_state = SocketStateClosed;
328+
LWIP_BEGIN();
329+
rsrc_obj->selecting_process_id = INVALID_PROCESS_ID;
330+
if (rsrc_obj->socket_state & SocketStateTCP) {
331+
if (rsrc_obj->socket_state & SocketStateTCPListening) {
332+
(void) tcp_close(rsrc_obj->tcp_pcb);
333+
} else {
334+
tcp_abort(rsrc_obj->tcp_pcb);
339335
}
340-
LWIP_END();
336+
rsrc_obj->tcp_pcb = NULL;
337+
rsrc_obj->socket_state = SocketStateClosed;
338+
} else if (rsrc_obj->socket_state & SocketStateUDP) {
339+
udp_remove(rsrc_obj->udp_pcb);
340+
rsrc_obj->udp_pcb = NULL;
341+
rsrc_obj->socket_state = SocketStateClosed;
341342
}
343+
LWIP_END();
342344
#endif
343345

344346
SMP_RWLOCK_UNLOCK(rsrc_obj->socket_lock);
347+
348+
// We're no longer monitoring so we can decrement ref count
345349
refc_binary_decrement_refcount(rsrc_refc, caller_env->global);
346350
}
347351

@@ -949,13 +953,16 @@ static term nif_socket_select_read(Context *ctx, int argc, term argv[])
949953
RAISE_ERROR(BADARG_ATOM);
950954
}
951955

956+
struct RefcBinary *rsrc_refc = refc_binary_from_data(rsrc_obj);
952957
SMP_RWLOCK_WRLOCK(rsrc_obj->socket_lock);
953958

954959
ErlNifEnv *env = erl_nif_env_from_context(ctx);
955960
if (rsrc_obj->selecting_process_id != ctx->process_id && rsrc_obj->selecting_process_id != INVALID_PROCESS_ID) {
956961
// demonitor can fail if process is gone.
957962
enif_demonitor_process(env, rsrc_obj, &rsrc_obj->selecting_process_monitor);
958963
rsrc_obj->selecting_process_id = INVALID_PROCESS_ID;
964+
// decrement ref count as we are demonitoring
965+
refc_binary_decrement_refcount(rsrc_refc, ctx->global);
959966
}
960967
// Monitor first as select is less likely to fail and it's less expensive to demonitor
961968
// if select fails than to stop select if monitor fails
@@ -964,6 +971,8 @@ static term nif_socket_select_read(Context *ctx, int argc, term argv[])
964971
SMP_RWLOCK_UNLOCK(rsrc_obj->socket_lock);
965972
RAISE_ERROR(NOPROC_ATOM);
966973
}
974+
// increment ref count so the resource doesn't go away until monitor is fired
975+
refc_binary_increment_refcount(rsrc_refc);
967976
rsrc_obj->selecting_process_id = ctx->process_id;
968977
}
969978

@@ -980,6 +989,7 @@ static term nif_socket_select_read(Context *ctx, int argc, term argv[])
980989
enif_demonitor_process(env, rsrc_obj, &rsrc_obj->selecting_process_monitor);
981990
rsrc_obj->selecting_process_id = INVALID_PROCESS_ID;
982991
SMP_RWLOCK_UNLOCK(rsrc_obj->socket_lock);
992+
refc_binary_decrement_refcount(rsrc_refc, ctx->global);
983993
RAISE_ERROR(BADARG_ATOM);
984994
}
985995
}
@@ -1026,6 +1036,7 @@ static term nif_socket_select_read(Context *ctx, int argc, term argv[])
10261036
enif_demonitor_process(env, rsrc_obj, &rsrc_obj->selecting_process_monitor);
10271037
LWIP_END();
10281038
SMP_RWLOCK_UNLOCK(rsrc_obj->socket_lock);
1039+
refc_binary_decrement_refcount(rsrc_refc, ctx->global);
10291040
RAISE_ERROR(BADARG_ATOM);
10301041
}
10311042
LWIP_END();
@@ -1048,7 +1059,12 @@ static term nif_socket_select_stop(Context *ctx, int argc, term argv[])
10481059
}
10491060
// Avoid the race condition with select object here.
10501061
SMP_RWLOCK_WRLOCK(rsrc_obj->socket_lock);
1051-
rsrc_obj->selecting_process_id = INVALID_PROCESS_ID;
1062+
if (rsrc_obj->selecting_process_id != INVALID_PROCESS_ID) {
1063+
enif_demonitor_process(erl_nif_env_from_context(ctx), rsrc_obj, &rsrc_obj->selecting_process_monitor);
1064+
rsrc_obj->selecting_process_id = INVALID_PROCESS_ID;
1065+
struct RefcBinary *rsrc_refc = refc_binary_from_data(rsrc_obj);
1066+
refc_binary_decrement_refcount(rsrc_refc, ctx->global);
1067+
}
10521068
#if OTP_SOCKET_BSD
10531069
if (UNLIKELY(enif_select(erl_nif_env_from_context(ctx), rsrc_obj->fd, ERL_NIF_SELECT_STOP, rsrc_obj, NULL, term_nil()) < 0)) {
10541070
RAISE_ERROR(BADARG_ATOM);

src/platforms/esp32/components/avm_builtins/network_driver.c

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -690,7 +690,7 @@ static void start_network(Context *ctx, term pid, term ref, term config)
690690
port_send_reply(ctx, pid, ref, error);
691691
return;
692692
}
693-
if (UNLIKELY((err = esp_wifi_set_storage(WIFI_STORAGE_RAM)) != ESP_OK)) {
693+
if (UNLIKELY((err = esp_wifi_set_storage(WIFI_STORAGE_FLASH)) != ESP_OK)) {
694694
ESP_LOGE(TAG, "Failed to set ESP WiFi storage");
695695
term error = port_create_error_tuple(ctx, term_from_int(err));
696696
port_send_reply(ctx, pid, ref, error);
@@ -814,6 +814,9 @@ static void stop_network(Context *ctx)
814814
{
815815
// Stop unregister event callbacks so they dont trigger during shutdown.
816816
esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler);
817+
esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler);
818+
esp_event_handler_unregister(IP_EVENT, IP_EVENT_AP_STAIPASSIGNED, &event_handler);
819+
esp_event_handler_unregister(sntp_event_base, SNTP_EVENT_BASE_SYNC, &event_handler);
817820

818821
esp_netif_t *sta_wifi_interface = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
819822
esp_netif_t *ap_wifi_interface = esp_netif_get_handle_from_ifkey("WIFI_AP_DEF");
@@ -833,12 +836,6 @@ static void stop_network(Context *ctx)
833836
// Stop sntp (ignore OK, or not configured error)
834837
esp_sntp_stop();
835838

836-
// Delete network event loop
837-
esp_err_t err = esp_event_loop_delete_default();
838-
if (err != ESP_OK) {
839-
ESP_LOGE(TAG, "Invalid state error while deleting event loop, continuing network shutdown...");
840-
}
841-
842839
// Destroy existing netif interfaces
843840
if (ap_wifi_interface != NULL) {
844841
esp_netif_destroy_default_wifi(ap_wifi_interface);

src/platforms/esp32/components/avm_sys/sys.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,12 @@ static const char *const esp32_c2_atom = "\x8" "esp32_c2";
8787
static const char *const esp32_c3_atom = "\x8" "esp32_c3";
8888
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 0)
8989
static const char *const esp32_c6_atom = "\x8" "esp32_c6";
90-
#endif
9190
static const char *const esp32_h2_atom = "\x8" "esp32_h2";
9291
#endif
92+
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)
93+
static const char *const esp32_p4_atom = "\x8" "esp32_p4";
94+
#endif
95+
#endif
9396
static const char *const emb_flash_atom = "\x9" "emb_flash";
9497
static const char *const bgn_atom = "\x3" "bgn";
9598
static const char *const ble_atom = "\x3" "ble";
@@ -457,9 +460,13 @@ static term get_model(Context *ctx, esp_chip_model_t model)
457460
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 0)
458461
case CHIP_ESP32C6:
459462
return globalcontext_make_atom(ctx->global, esp32_c6_atom);
460-
#endif
461463
case CHIP_ESP32H2:
462464
return globalcontext_make_atom(ctx->global, esp32_h2_atom);
465+
#endif
466+
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)
467+
case CHIP_ESP32P4:
468+
return globalcontext_make_atom(ctx->global, esp32_p4_atom);
469+
#endif
463470
default:
464471
return UNDEFINED_ATOM;
465472
}

src/platforms/esp32/test/main/test_erl_sources/test_wifi_example.erl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
start() ->
2626
case verify_platform(atomvm:platform()) of
2727
ok ->
28+
ok = start_network(),
29+
ok = network:stop(),
2830
start_network(),
2931
loop(0);
3032
Error ->

src/platforms/stm32/src/lib/stm_sys.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,5 +82,7 @@ void sys_enable_flash_cache(void);
8282
void *_sbrk_r(struct _reent *, ptrdiff_t);
8383
// This function may be defined to relocate the heap.
8484
void local_heap_setup(uint8_t **start, uint8_t **end);
85+
void sys_enable_core_periph_clocks();
86+
bool sys_lock_pin(GlobalContext *glb, uint32_t gpio_bank, uint16_t pin_num);
8587

8688
#endif /* _STM_SYS_H_ */

0 commit comments

Comments
 (0)