Skip to content

Commit

Permalink
Merge branch 'master' into gc-array-replace
Browse files Browse the repository at this point in the history
  • Loading branch information
kasperl committed May 17, 2024
2 parents 571e2b0 + 55101f8 commit 7433173
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 30 deletions.
68 changes: 57 additions & 11 deletions include/toit/toit.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ extern "C" {
* @brief Toit error constants.
*/
typedef enum {
TOIT_ERR_SUCCESS = 0, /*!< The operation succeeded (no error). */
TOIT_OK = 0, /*!< The operation succeeded (no error). */
TOIT_ERR_OOM, /*!< Out of memory. */
TOIT_ERR_NO_SUCH_RECEIVER, /*!< The receiver of a system message didn't exist. */
TOIT_ERR_NOT_FOUND, /*!< The corresponding resource was not found. */
Expand Down Expand Up @@ -51,7 +51,7 @@ typedef struct {
*
* @param user_data The user data passed to `toit_msg_add_handler`.
* @param context The context of the message handler.
* @return toit_err_t The result of the callback. Must be `TOIT_ERR_SUCCESS`.
* @return toit_err_t The result of the callback. Must be `TOIT_OK`.
*/
typedef toit_err_t (*toit_msg_on_created_cb_t)(void* user_data, toit_msg_context_t* context);

Expand All @@ -67,7 +67,7 @@ typedef toit_err_t (*toit_msg_on_created_cb_t)(void* user_data, toit_msg_context
* @param sender The PID of the sender.
* @param data The data of the message. Must be freed by the receiver.
* @param length The length of the data.
* @return toit_err_t The result of the callback. Must be `TOIT_ERR_SUCCESS`.
* @return toit_err_t The result of the callback. Must be `TOIT_OK`.
*/
typedef toit_err_t (*toit_msg_on_message_cb_t)(void* user_data, int sender, uint8_t* data, int length);

Expand All @@ -92,7 +92,7 @@ typedef toit_err_t (*toit_msg_on_message_cb_t)(void* user_data, int sender, uint
* @param rpc_handle The handle to the request.
* @param data The data of the request. Must be freed by the receiver.
* @param length The length of the data.
* @return toit_err_t The result of the callback. Must be `TOIT_ERR_SUCCESS`.
* @return toit_err_t The result of the callback. Must be `TOIT_OK`.
*/
typedef toit_err_t (*toit_msg_on_request_cb_t)(void* user_data,
int sender,
Expand All @@ -107,7 +107,7 @@ typedef toit_err_t (*toit_msg_on_request_cb_t)(void* user_data,
* point, the user data is no longer needed and can be freed.
*
* @param user_data The user data passed to `toit_msg_add_handler`.
* @return toit_err_t The result of the callback. Must be `TOIT_ERR_SUCCESS`.
* @return toit_err_t The result of the callback. Must be `TOIT_OK`.
*/
typedef toit_err_t (*toit_msg_on_removed_cb_t)(void* user_data);

Expand All @@ -121,6 +121,16 @@ typedef struct toit_msg_cbs_t {
toit_msg_on_removed_cb_t on_removed;
} toit_msg_cbs_t;

/**
* @brief Macro to create an empty set of message handler callbacks.
*/
#define TOIT_MSG_EMPTY_CBS() { \
.on_created = NULL, \
.on_message = NULL, \
.on_rpc_request = NULL, \
.on_removed = NULL, \
}

/**
* @brief Add a message handler for this service.
*
Expand All @@ -143,7 +153,9 @@ typedef struct toit_msg_cbs_t {
* @param id The unique identifier for the message handler.
* @param user_data The user data to pass to the callbacks.
* @param cbs The callbacks for the message handler.
* @return toit_err_t The result of adding the message handler.
* @return toit_err_t
* - TOIT_OK: The message handler was added successfully.
* - TOIT_ERR_OOM: Out of memory.
*/
toit_err_t toit_msg_add_handler(const char* id,
void* user_data,
Expand All @@ -155,7 +167,9 @@ toit_err_t toit_msg_add_handler(const char* id,
* Once the message handler is removed, the `on_removed` callback will be called.
*
* @param context The context of the message handler.
* @return toit_err_t The result of the call.
* @return toit_err_t
* - TOIT_OK: The message handler was removed successfully.
* - TOIT_ERR_NOT_FOUND: The message handler was not found.
*/
toit_err_t toit_msg_remove_handler(toit_msg_context_t* context);

Expand All @@ -177,7 +191,10 @@ toit_err_t toit_msg_remove_handler(toit_msg_context_t* context);
* @param data The data to send.
* @param length The length of the data.
* @param free_on_failure Whether to free the data if the message cannot be sent.
* @return toit_err_t The result of the call.
* @return toit_err_t
* - TOIT_OK: The message was sent successfully.
* - TOIT_ERR_NO_SUCH_RECEIVER: The target process does not exist.
* - TOIT_ERR_OOM: Out of memory, despite calling `toit_gc`.
*/
toit_err_t toit_msg_notify(toit_msg_context_t* context,
int target_pid,
Expand All @@ -198,7 +215,10 @@ toit_err_t toit_msg_notify(toit_msg_context_t* context,
* @param data The data to send.
* @param length The length of the data.
* @param free_on_failure Whether to free the data if the message cannot be sent.
* @return toit_err_t The result of the call.
* @return toit_err_t
* - TOIT_OK: The message was sent successfully.
* - TOIT_ERR_NO_SUCH_RECEIVER: The target process does not exist.
* - TOIT_ERR_OOM: Out of memory, despite calling `toit_gc`.
*/
toit_err_t toit_msg_request_reply(toit_msg_request_handle_t handle, uint8_t* data, int length, bool free_on_failure);

Expand All @@ -214,14 +234,18 @@ toit_err_t toit_msg_request_reply(toit_msg_request_handle_t handle, uint8_t* dat
* @param handle The handle to the request. This handle must have been received
* through the `on_rpc_request` callback.
* @param error The error message to send.
* @return toit_err_t The result of the call.
* @return toit_err_t
* - TOIT_OK: The failure message was sent successfully.
* - TOIT_ERR_NO_SUCH_RECEIVER: The target process does not exist.
* - TOIT_ERR_OOM: Out of memory, despite calling `toit_gc`.
*/
toit_err_t toit_msg_request_fail(toit_msg_request_handle_t handle, const char* error);

/**
* @brief Perform a garbage collection on all Toit processes.
*
* @return toit_err_t The result of the call.
* @return toit_err_t
* - TOIT_OK: The garbage collection was run successfully.
*/
toit_err_t toit_gc();

Expand All @@ -235,6 +259,28 @@ toit_err_t toit_gc();
*/
void* toit_malloc(size_t size);

/**
* @brief A wrapper around `calloc` that calls `toit_gc` if `calloc` fails.
*
* If `calloc` fails, this function calls `toit_gc` and then retries the allocation.
*
* @param nmemb The number of elements to allocate.
* @param size The size of each element.
* @return void* A pointer to the allocated memory, or `NULL` if the allocation failed.
*/
void* toit_calloc(size_t nmemb, size_t size);

/**
* @brief A wrapper around `realloc` that calls `toit_gc` if `realloc` fails.
*
* If `realloc` fails, this function calls `toit_gc` and then retries the allocation.
*
* @param ptr The pointer to the memory to reallocate.
* @param size The new size that is requested.
* @return void* A pointer to the allocated memory, or `NULL` if the reallocation failed.
*/
void* toit_realloc(void* ptr, size_t size);

#ifdef __cplusplus
}
#endif
42 changes: 35 additions & 7 deletions src/messaging.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1093,13 +1093,13 @@ toit_err_t toit_msg_add_handler(const char* id,
auto old = toit::registered_message_handlers;
auto list = toit::unvoid_cast<toit::RegisteredExternalMessageHandlerList*>(
malloc(sizeof(toit::RegisteredExternalMessageHandlerList)));
if (list == null) FATAL("[OOM during external process setup]");
if (list == null) return TOIT_ERR_OOM;
list->next = old;
list->registered_handler.id = id;
list->registered_handler.user_context = user_context;
list->registered_handler.callbacks = cbs;
toit::registered_message_handlers = list;
return TOIT_ERR_SUCCESS;
return TOIT_OK;
}

toit_err_t toit_msg_remove_handler(toit_msg_context_t* context) {
Expand All @@ -1110,15 +1110,15 @@ toit_err_t toit_msg_remove_handler(toit_msg_context_t* context) {
auto handler = entry.handler;
toit::id_handler_entry_mapping[i].handler = null;
delete handler;
return TOIT_ERR_SUCCESS;
return TOIT_OK;
}
}
return TOIT_ERR_NOT_FOUND;
}

static toit_err_t message_err_to_toit_err(toit::message_err_t err) {
switch (err) {
case toit::MESSAGE_OK: return TOIT_ERR_SUCCESS;
case toit::MESSAGE_OK: return TOIT_OK;
case toit::MESSAGE_OOM: return TOIT_ERR_OOM;
case toit::MESSAGE_NO_SUCH_RECEIVER: return TOIT_ERR_NO_SUCH_RECEIVER;
}
Expand All @@ -1131,26 +1131,40 @@ toit_err_t toit_msg_notify(toit_msg_context_t* context,
bool free_on_failure) {
auto handler = reinterpret_cast<toit::ExternalMessageHandler*>(context);
auto type = toit::SYSTEM_EXTERNAL_NOTIFICATION;
toit::message_err_t err = handler->send_with_err(target_pid, type, data, length, free_on_failure);
toit::message_err_t err = handler->send_with_err(target_pid, type, data, length, false);
if (err == toit::MESSAGE_OOM) {
toit_gc();
err = handler->send_with_err(target_pid, type, data, length, false);
}
if (free_on_failure && err != toit::MESSAGE_OK) free(data);
return message_err_to_toit_err(err);
}

toit_err_t toit_msg_request_fail(toit_msg_request_handle_t rpc_handle, const char* error) {
auto handler = reinterpret_cast<toit::ExternalMessageHandler*>(rpc_handle.context);
toit::message_err_t err = handler->reply_rpc(rpc_handle.sender, rpc_handle.request_handle, true, error, null, 0, false);
if (err == toit::MESSAGE_OOM) {
toit_gc();
err = handler->reply_rpc(rpc_handle.sender, rpc_handle.request_handle, true, error, null, 0, false);
}
return message_err_to_toit_err(err);
}

toit_err_t toit_msg_request_reply(toit_msg_request_handle_t rpc_handle, uint8_t* data, int length, bool free_on_failure) {
auto handler = reinterpret_cast<toit::ExternalMessageHandler*>(rpc_handle.context);
toit::message_err_t err = handler->reply_rpc(rpc_handle.sender, rpc_handle.request_handle, false, null, data, length, free_on_failure);
toit::message_err_t err = handler->reply_rpc(rpc_handle.sender, rpc_handle.request_handle, false, null, data, length, false);
if (err == toit::MESSAGE_OOM) {
toit_gc();
err = handler->reply_rpc(rpc_handle.sender, rpc_handle.request_handle, false, null, data, length, false);
}
if (free_on_failure && err != toit::MESSAGE_OK) free(data);
return message_err_to_toit_err(err);
}

// TODO(florian): this isn't really a messaging function. It should probably be somewhere else.
toit_err_t toit_gc() {
toit::VM::current()->scheduler()->gc(NULL, true, true);
return TOIT_ERR_SUCCESS;
return TOIT_OK;
}

void* toit_malloc(size_t size) {
Expand All @@ -1160,4 +1174,18 @@ void* toit_malloc(size_t size) {
return malloc(size);
}

void* toit_calloc(size_t nmemb, size_t size) {
void* ptr = calloc(nmemb, size);
if (ptr != NULL) return ptr;
toit_gc();
return calloc(nmemb, size);
}

void* toit_realloc(void* ptr, size_t size) {
void* new_ptr = realloc(ptr, size);
if (new_ptr != NULL) return new_ptr;
toit_gc();
return realloc(ptr, size);
}

} // Extern C.
7 changes: 7 additions & 0 deletions src/resources/ethernet_esp32.cc
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,11 @@ PRIMITIVE(init) {
PRIMITIVE(init_spi) {
ARGS(int, mac_chip, SpiResourceGroup, spi, int, frequency, int, cs, int, int_num)

#ifndef CONFIG_ETH_SPI_ETHERNET_W5500
if (mac_chip == MAC_CHIP_W5500) {
return Primitive::os_error(ESP_ERR_NOT_SUPPORTED, process);
}
#endif
ByteArray* proxy = process->object_heap()->allocate_proxy();
if (proxy == null) FAIL(ALLOCATION_FAILED);

Expand Down Expand Up @@ -323,13 +328,15 @@ PRIMITIVE(init_spi) {
esp_eth_mac_t* mac = null;
esp_eth_phy_t* phy = null;
switch (mac_chip) {
#ifdef CONFIG_ETH_SPI_ETHERNET_W5500
case MAC_CHIP_W5500: {
eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(spi_host, &spi_config);
w5500_config.int_gpio_num = int_num;
mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config);
phy = esp_eth_phy_new_w5500(&phy_config);
break;
}
#endif
}
if (!phy || !mac) {
ethernet_pool.put(id);
Expand Down
23 changes: 11 additions & 12 deletions tests/ctest/external-messaging2-toit-run-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,20 @@ static toit_err_t on_created(void* user_data, toit_msg_context_t* context) {
test_service_t* test_service = (test_service_t*)user_data;
printf("created external message handler %d\n", test_service->id);
test_service->msg_context = context;
return TOIT_ERR_SUCCESS;
return TOIT_OK;
}

static toit_err_t on_message(void* user_data, int sender, uint8_t* data, int length) {
test_service_t* test_service = (test_service_t*)user_data;
printf("received message in C %d\n", test_service->id);
toit_msg_context_t* context = ((test_service_t*)(user_data))->msg_context;
if (toit_msg_notify(context, sender, data, length, true) != TOIT_ERR_SUCCESS) {
if (toit_msg_notify(context, sender, data, length, true) != TOIT_OK) {
printf("unable to send\n");
}
if (length == 2 && ((char*)data)[0] == 99 && ((char*)data)[1] == 99) {
toit_msg_remove_handler(context);
}
return TOIT_ERR_SUCCESS;
return TOIT_OK;
}

static toit_err_t on_rpc_request(void* user_data, int sender, int function, toit_msg_request_handle_t handle, uint8_t* data, int length) {
Expand All @@ -47,18 +47,18 @@ static toit_err_t on_rpc_request(void* user_data, int sender, int function, toit
toit_gc();
data[0] = 0;
}
if (toit_msg_request_reply(handle, data, length, true) != TOIT_ERR_SUCCESS) {
if (toit_msg_request_reply(handle, data, length, true) != TOIT_OK) {
printf("unable to reply\n");
}
}
return TOIT_ERR_SUCCESS;
return TOIT_OK;
}

static toit_err_t on_removed(void* user_data) {
test_service_t* test_service = (test_service_t*)user_data;
printf("freeing user data %d\n", test_service->id);
free(user_data);
return TOIT_ERR_SUCCESS;
return TOIT_OK;
}

static void __attribute__((constructor)) init() {
Expand All @@ -80,11 +80,10 @@ static void __attribute__((constructor)) init2() {
test_service_t* test_service = (test_service_t*)malloc(sizeof(test_service_t));
test_service->id = 1;
test_service->msg_context = NULL;
toit_msg_cbs_t cbs = {
.on_created = on_created,
.on_message = on_message,
.on_rpc_request = on_rpc_request,
.on_removed = on_removed,
};
toit_msg_cbs_t cbs = TOIT_MSG_EMPTY_CBS();
cbs.on_created = on_created;
cbs.on_message = on_message;
cbs.on_rpc_request = on_rpc_request;
cbs.on_removed = on_removed;
toit_msg_add_handler("toit.io/external-test1", test_service, cbs);
}

0 comments on commit 7433173

Please sign in to comment.