Skip to content

Commit

Permalink
External messaging. (#1807)
Browse files Browse the repository at this point in the history
  • Loading branch information
floitsch committed May 13, 2024
1 parent 9320b4d commit 1005c0a
Show file tree
Hide file tree
Showing 22 changed files with 815 additions and 45 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ endif()
set(TOIT_GENERIC_FLAGS "${TOIT_GENERIC_FLAGS} -Wall -ffunction-sections -fdata-sections")

include_directories(
"${TOIT_SDK_SOURCE_DIR}/include"
"${IDF_PATH}/components/mbedtls/mbedtls/include"
)

Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,11 @@ else
endif

.PHONY: all
all: sdk
all: sdk build-test-assets

.PHONY: debug
debug:
LOCAL_CXXFLAGS="-O0" $(MAKE) BUILD_TYPE=Debug
cmake -E env LOCAL_CFLAGS="-O0" LOCAL_CXXFLAGS="-O0" $(MAKE) BUILD_TYPE=Debug

.PHONY: sdk
sdk: tools toit-tools version-file
Expand Down
86 changes: 86 additions & 0 deletions include/toit/toit.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright (C) 2024 Toitware ApS.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 only.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// The license can be found in the file `LICENSE` in the top level
// directory of this repository.

#pragma once

#ifdef __cplusplus
extern "C" {
#else
#include <stdbool.h>
#endif

/*
* C interface for Toit's external API.
*/

typedef enum {
// The operation succeeded.
TOIT_ERR_SUCCESS = 0,
// The operation encountered an out-of-memory error.
TOIT_ERR_OOM,
// An error, for when the receiver of a system message didn't exist.
TOIT_ERR_NO_SUCH_RECEIVER,
// The corresponding resource was not found.
TOIT_ERR_NOT_FOUND,
// An unknown error.
TOIT_ERR_ERROR,
} toit_err_t;

const int TOIT_MSG_RESERVED_TYPES = 64;

struct toit_msg_context_t;
typedef struct toit_msg_context_t toit_msg_context_t;

typedef struct {
int sender;
int request_handle;
toit_msg_context_t* context;
} toit_msg_request_handle_t;

typedef toit_err_t (*toit_msg_on_created_cb_t)(void* user_data, toit_msg_context_t* context);
typedef toit_err_t (*toit_msg_on_message_cb_t)(void* user_data, int sender, void* data, int length);
typedef toit_err_t (*toit_msg_on_request_cb_t)(void* user_data,
int sender,
int function,
toit_msg_request_handle_t rpc_handle,
void* data, int length);
typedef toit_err_t (*toit_msg_on_removed_cb_t)(void* user_data);

typedef struct toit_msg_cbs_t {
toit_msg_on_created_cb_t on_created;
toit_msg_on_message_cb_t on_message;
toit_msg_on_request_cb_t on_rpc_request;
toit_msg_on_removed_cb_t on_removed;
} toit_msg_cbs_t;

toit_err_t toit_msg_add_handler(const char* id,
void* user_data,
toit_msg_cbs_t cbs);

toit_err_t toit_msg_remove_handler(toit_msg_context_t* context);

toit_err_t toit_msg_notify(toit_msg_context_t* context,
int target_pid,
void* data, int length,
bool free_on_failure);

toit_err_t toit_msg_request_reply(toit_msg_request_handle_t handle, void* data, int length, bool free_on_failure);
toit_err_t toit_msg_request_fail(toit_msg_request_handle_t handle, const char* error);

toit_err_t toit_gc();

#ifdef __cplusplus
}
#endif
19 changes: 19 additions & 0 deletions lib/core/message_.toit
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ SYSTEM-RPC-CANCEL_ ::= 5
SYSTEM-RPC-NOTIFY-TERMINATED_ ::= 6
SYSTEM-RPC-NOTIFY-RESOURCE_ ::= 7

// System message types for external notifications.
SYSTEM-EXTERNAL_NOTIFICATION_ ::= 8

RESERVED-MESSAGE-TYPES_ ::= 64

/**
Sends the $message with $type to the process identified by $pid and
returns whether the $message was delivered.
Expand All @@ -29,6 +34,14 @@ process-send_ pid/int type/int message -> bool:
serialization-failure_ it[0]
throw it

/**
Returns the process ID for the process with the given external $id.
If no process with the external ID exists, returns -1.
*/
pid-for-external-id_ id/string -> int:
#primitive.core.pid-for-external-id

/** Registered system message handlers for this process. */
system-message-handlers_ ::= {:}

Expand All @@ -45,6 +58,12 @@ Sets the $handler as the system message handler for message of the $type.
set-system-message-handler_ type/int handler/SystemMessageHandler_:
system-message-handlers_[type] = handler

/**
Removes the handler for the given $type.
*/
clear-system-message-handler_ type/int:
system-message-handlers_.remove type

/** Flag to track if we're currently processing messages. */
is-processing-messages_ := false

Expand Down
83 changes: 83 additions & 0 deletions lib/system/external.toit
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Copyright (C) 2024 Toitware ApS. All rights reserved.
// Use of this source code is governed by an MIT-style license that can be
// found in the lib/LICENSE file.
import io
import rpc

clients_ ::= {:}
notification-listeners_ := 0
notification-handler_/ExternalMessageHandler_? := null

class Client:
pid/int
id/string
on-notify_/Lambda? := null
is-closed_/bool := false

constructor.private_ .pid .id .on-notify_:

static open id/string --on-notify/Lambda?=null -> Client?:
pid := pid-for-external-id_ id
if pid == -1: throw "NOT_FOUND"
if clients_.contains pid: throw "ALREADY_IN_USE"
result := Client.private_ pid id on-notify
clients_[pid] = result
return result

close -> none:
if is-closed_: return
// Go through the function so that the ref-counting is correct.
set-on-notify null
is-closed_ = true

is-closed -> bool:
return is-closed_

/** Helper to convert the $message to a ByteArray. */
encode-message_ message/io.Data --copy/bool -> ByteArray:
bytes/ByteArray := ?
if copy or message is not ByteArray:
bytes = ByteArray message.byte-size
message.write-to-byte-array bytes --at=0 0 message.byte-size
else:
bytes = message as ByteArray
return bytes

notify message/io.Data --copy/bool=true:
if is-closed_: throw "ALREADY_CLOSED"
bytes := encode-message_ message --copy=copy
process-send_ pid SYSTEM-EXTERNAL-NOTIFICATION_ bytes

request function/int message/ByteArray --copy/bool=true -> any:
if is-closed_: throw "ALREADY_CLOSED"
bytes := encode-message_ message --copy=copy
return rpc.invoke pid function bytes

set-on-notify callback/Lambda? -> none:
if is-closed_: throw "ALREADY_CLOSED"
if on-notify_ != null: notification-listeners_--
on-notify_ = callback
if callback:
notification-listeners_++
ExternalMessageHandler_.handle-listener-change

class ExternalMessageHandler_ implements SystemMessageHandler_:
static TYPE ::= SYSTEM-EXTERNAL-NOTIFICATION_

close -> none:
clear-system-message-handler_ TYPE

on-message type/int gid/int pid/int argument -> none:
client/Client? := clients_.get pid
if not client: return
if client.on-notify_:
client.on-notify_.call argument

static handle-listener-change -> none:
if notification-listeners_ > 0 and not notification-handler_:
notification-handler_ = ExternalMessageHandler_
set-system-message-handler_ TYPE notification-handler_
else if notification-listeners_ <= 0 and notification-handler_:
notification-handler_.close
notification-handler_ = null
3 changes: 2 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ set_source_files_properties(interpreter_run.cc PROPERTIES COMPILE_OPTIONS "-O3;$
set_source_files_properties(utils.cc PROPERTIES COMPILE_FLAGS "-DTOIT_MODEL=\"\\\"${TOIT_MODEL}\\\"\" -DVM_GIT_INFO=\"\\\"${VM_GIT_INFO}\\\"\" -DVM_GIT_VERSION=\"\\\"${TOIT_GIT_VERSION}\\\"\"")

set(GEN_DIR "${PROJECT_BINARY_DIR}/generated")

set(BOOT_SNAPSHOT ${GEN_DIR}/toit.run.snapshot)
set(BOOT_SNAPSHOT_CC ${GEN_DIR}/toit.run.snapshot.cc)
set(TOIT_SNAPSHOT ${GEN_DIR}/toit.snapshot)
Expand All @@ -131,6 +130,8 @@ add_custom_command(
WORKING_DIRECTORY "${GEN_DIR}"
)

add_custom_target(build_boot_snapshot DEPENDS ${BOOT_SNAPSHOT_CC})

add_custom_command(
OUTPUT "${TOIT_SNAPSHOT_CC}"
# We can't use ${TOIT_SNAPSHOT} here, as that would include the full path.
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/propagation/type_primitive_core.cc
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,8 @@ TYPE_PRIMITIVE(process_send) {
failure.add_array(program);
}

TYPE_PRIMITIVE_INT(pid_for_external_id)

TYPE_PRIMITIVE(spawn) {
result.add_smi(program);
failure.add_string(program);
Expand Down

0 comments on commit 1005c0a

Please sign in to comment.