Skip to content

Commit

Permalink
Unregister processes when they die
Browse files Browse the repository at this point in the history
Adds the function `globalcontext_maybe_unregister_process_id` to globalcontext.c
to allow removing the appropriate entry from the registered atoms table when the
associated context is destroyed.

Signed-off-by: Winford <winford@object.stream>
  • Loading branch information
UncleGrumpy committed Jun 16, 2023
1 parent 187e414 commit 49eb33e
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 0 deletions.
4 changes: 4 additions & 0 deletions src/libAtomVM/context.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ void context_destroy(Context *ctx)
// Another process can get an access to our mailbox until this point.
synclist_remove(&ctx->global->processes_table, &ctx->processes_table_head);

// Ensure process is not registered
globalcontext_maybe_unregister_process_id(ctx->global, ctx->process_id);

// When monitor message is sent, process is no longer in the table.
context_monitors_handle_terminate(ctx);

Expand All @@ -135,6 +138,7 @@ void context_destroy(Context *ctx)
if (ctx->platform_data) {
free(ctx->platform_data);
}

free(ctx);
}

Expand Down
17 changes: 17 additions & 0 deletions src/libAtomVM/globalcontext.c
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,23 @@ bool globalcontext_unregister_process(GlobalContext *glb, int atom_index)
return false;
}

bool globalcontext_maybe_unregister_process_id(GlobalContext *glb, int target_process_id)
{
struct ListHead *registered_processes_list = synclist_wrlock(&glb->registered_processes);
struct ListHead *item;
LIST_FOR_EACH (item, registered_processes_list) {
const struct RegisteredProcess *registered_process = GET_LIST_ENTRY(item, struct RegisteredProcess, registered_processes_list_head);
if (registered_process->local_process_id == target_process_id) {
list_remove(item);
free(item);
synclist_unlock(&glb->registered_processes);
return true;
}
}
synclist_unlock(&glb->registered_processes);
return false;
}

int globalcontext_get_registered_process(GlobalContext *glb, int atom_index)
{
struct ListHead *registered_processes_list = synclist_rdlock(&glb->registered_processes);
Expand Down
11 changes: 11 additions & 0 deletions src/libAtomVM/globalcontext.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,17 @@ int globalcontext_get_registered_process(GlobalContext *glb, int atom_index);
*/
bool globalcontext_unregister_process(GlobalContext *glb, int atom_index);

/**
* @brief Remove entry from registered atoms by process id
*
* @details Unregister a process with a certain process id. This is used when a process dies to ensure
* the process is not registered and remove it from the registered atoms table if it is.
* @param glb the global context, each registered process will be globally available for that context.
* @param process_id the process id of the entry to remove.
* @returns \c true if the process was unregistered, \c false otherwise
*/
bool globalcontext_maybe_unregister_process_id(GlobalContext *glb, int process_id);

/**
* @brief equivalent to globalcontext_insert_atom_maybe_copy(glb, atom_string, 0);
*/
Expand Down
2 changes: 2 additions & 0 deletions tests/erlang_tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ compile_erlang(match)
compile_erlang(if_test)
compile_erlang(sleep)
compile_erlang(hello_world)
compile_erlang(whereis_dead_process)
compile_erlang(whereis_fail)
compile_erlang(register_unregister)
compile_erlang(try_noerror)
Expand Down Expand Up @@ -518,6 +519,7 @@ add_custom_target(erlang_test_modules DEPENDS
if_test.beam
sleep.beam
hello_world.beam
whereis_dead_process.beam
whereis_fail.beam
register_unregister.beam
try_noerror.beam
Expand Down
32 changes: 32 additions & 0 deletions tests/erlang_tests/whereis_dead_process.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
%
% This file is part of AtomVM.
%
% Copyright 2023 Winford (Uncle Grumpy) <winford@object.stream>
%
% Licensed under the Apache License, Version 2.0 (the "License");
% you may not use this file except in compliance with the License.
% You may obtain a copy of the License at
%
% http://www.apache.org/licenses/LICENSE-2.0
%
% Unless required by applicable law or agreed to in writing, software
% distributed under the License is distributed on an "AS IS" BASIS,
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
% See the License for the specific language governing permissions and
% limitations under the License.
%
% SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
%

-module(whereis_dead_process).

-export([start/0]).

start() ->
spawn(fun() -> register(foo, self()) end),
result_to_int(whereis(foo)).

result_to_int(undefined) ->
0;
result_to_int(_) ->
1.
1 change: 1 addition & 0 deletions tests/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ struct Test tests[] = {
TEST_CASE_EXPECTED(match, 5),
TEST_CASE_EXPECTED(if_test, 5),
TEST_CASE(sleep),
TEST_CASE(whereis_dead_process),
TEST_CASE_EXPECTED(whereis_fail, 2),
TEST_CASE_EXPECTED(try_noerror, 1),
TEST_CASE_EXPECTED(catch_badmatch, 1),
Expand Down

0 comments on commit 49eb33e

Please sign in to comment.