-
Notifications
You must be signed in to change notification settings - Fork 75
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
External messaging. #1807
External messaging. #1807
Changes from 6 commits
6ac9274
4f84e48
7ac6943
c976533
a58d4f2
97140ad
b3085d3
ee6705e
bf406b2
ce137c1
4d21470
17977a7
e30034a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,44 @@ | ||||||||
// Copyright (C) 2023 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. | ||||||||
|
||||||||
/* | ||||||||
* C interface for Toit's messaging API. | ||||||||
*/ | ||||||||
|
||||||||
#pragma once | ||||||||
|
||||||||
#include <stdint.h> | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you need these? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done. |
||||||||
#include <stdbool.h> | ||||||||
|
||||||||
#ifdef __cplusplus | ||||||||
extern "C" { | ||||||||
#endif | ||||||||
|
||||||||
struct HandlerContext; | ||||||||
typedef struct HandlerContext HandlerContext; | ||||||||
|
||||||||
void toit_register_external_message_handler(void* user_context, | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe add/remove instead of register/release? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done. |
||||||||
int requested_pid, | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As discussed, I think it would be better with a symbolic name here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will do that in a follow-up PR. |
||||||||
void (*create_handler)(void* user_context, HandlerContext* handler_context)); | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I'd introduce a type for the create handler function. It feels cleaner. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done. |
||||||||
void toit_set_callbacks(HandlerContext* handler_context, | ||||||||
void (*callback)(void* user_context, int sender, int type, void* data, int length), | ||||||||
void (*release)(void* user_context)); | ||||||||
|
||||||||
bool toit_send_message(HandlerContext* handler_context, int target_pid, int type, void* data, int length, bool free_on_failure); | ||||||||
void toit_release_handler(HandlerContext* handler_context); | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done. |
||||||||
|
||||||||
#ifdef __cplusplus | ||||||||
} | ||||||||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,6 +14,7 @@ | |
// directory of this repository. | ||
|
||
#include "messaging.h" | ||
#include <toit/cmessaging.h> | ||
|
||
#include "objects.h" | ||
#include "process.h" | ||
|
@@ -834,4 +835,104 @@ void ExternalSystemMessageHandler::collect_garbage(bool try_hard) { | |
} | ||
} | ||
|
||
namespace { | ||
|
||
struct RegisteredHandler { | ||
int requested_pid; | ||
void* user_context; | ||
void (*create_handler)(void* user_context, HandlerContext* handler_context); | ||
}; | ||
|
||
struct RegisteredHandlerList { | ||
RegisteredHandlerList* next; | ||
RegisteredHandler handler; | ||
}; | ||
|
||
RegisteredHandlerList* registered_handlers = null; | ||
|
||
typedef void (*ReceiverCallback)(void* user_context, int sender, int type, void* data, int length); | ||
typedef void (*ReleaseCallback)(void* user_context); | ||
|
||
class ExternalMessageHandler : public ExternalSystemMessageHandler { | ||
public: | ||
ExternalMessageHandler(VM* vm, | ||
void* user_context) | ||
: ExternalSystemMessageHandler(vm) | ||
, user_context_(user_context) {} | ||
virtual ~ExternalMessageHandler() { | ||
if (release_ != null) release_(user_context_); | ||
} | ||
|
||
void on_message(int pid, int type, void* data, int length) override { | ||
if (on_message_ == null) return; | ||
printf("Calling on-message %p\n", user_context_); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Drop the debug printing. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done. |
||
on_message_(user_context_, pid, type, data, length); | ||
} | ||
|
||
void set_on_message(ReceiverCallback on_message) { | ||
on_message_ = on_message; | ||
} | ||
|
||
void set_release(ReleaseCallback release) { | ||
release_ = release; | ||
} | ||
|
||
private: | ||
void* user_context_; | ||
ReceiverCallback on_message_ = null; | ||
ReleaseCallback release_ = null; | ||
}; | ||
|
||
} // anonymous namespace. | ||
|
||
void create_and_start_external_message_handlers(VM* vm) { | ||
for (RegisteredHandlerList* list = registered_handlers; list != null; list = list->next) { | ||
// TODO(florian): use requested pid. | ||
ExternalMessageHandler* handler = _new ExternalMessageHandler(vm, list->handler.user_context); | ||
if (!handler->start()) { | ||
FATAL("[failed to start external message handler]"); | ||
} | ||
list->handler.create_handler(list->handler.user_context, reinterpret_cast<HandlerContext*>(handler)); | ||
} | ||
// Free the list. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you keep symbolic names in the list, you should probably not free it here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I allocated a mapping object. |
||
while (registered_handlers != null) { | ||
RegisteredHandlerList* next = registered_handlers->next; | ||
free(registered_handlers); | ||
registered_handlers = next; | ||
} | ||
} | ||
|
||
} // namespace toit | ||
|
||
extern "C" { | ||
|
||
void toit_register_external_message_handler(void* user_context, | ||
int requested_pid, | ||
void (*create_handler)(void* user_context, HandlerContext* handler_context)) { | ||
auto old = toit::registered_handlers; | ||
auto list = reinterpret_cast<toit::RegisteredHandlerList*>(malloc(sizeof(toit::RegisteredHandlerList))); | ||
if (list == null) return; | ||
list->next = old; | ||
list->handler.requested_pid = requested_pid; | ||
list->handler.user_context = user_context; | ||
list->handler.create_handler = create_handler; | ||
toit::registered_handlers = list; | ||
} | ||
|
||
void toit_set_callbacks(HandlerContext* handler_context, toit::ReceiverCallback on_message, toit::ReleaseCallback release) { | ||
auto handler = reinterpret_cast<toit::ExternalMessageHandler*>(handler_context); | ||
handler->set_on_message(on_message); | ||
handler->set_release(release); | ||
} | ||
|
||
bool toit_send_message(HandlerContext* handler_context, int target_pid, int type, void* data, int length, bool free_on_failure) { | ||
auto handler = reinterpret_cast<toit::ExternalMessageHandler*>(handler_context); | ||
return handler->send(target_pid, type, data, length, free_on_failure); | ||
} | ||
|
||
void toit_release_handler(HandlerContext* handler_context) { | ||
auto handler = reinterpret_cast<toit::ExternalMessageHandler*>(handler_context); | ||
delete handler; | ||
} | ||
|
||
} // Extern C. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,7 @@ | |
#include "top.h" | ||
#include "run.h" | ||
#include "interpreter.h" | ||
#include "messaging.h" | ||
#include "scheduler.h" | ||
#include "vm.h" | ||
#include "os.h" | ||
|
@@ -65,6 +66,7 @@ int run_program(SnapshotBundle boot_bundle, SnapshotBundle application_bundle, c | |
vm.load_platform_event_sources(); | ||
ProgramImage boot_image = read_image_from_bundle(boot_bundle); | ||
int group_id = vm.scheduler()->next_group_id(); | ||
create_and_start_external_message_handlers(&vm); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it important that you do this after you've gotten the group_id? If not, I'd try to do this before, maybe just after There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done. |
||
if (boot_image.is_valid()) { | ||
exit = vm.scheduler()->run_boot_program( | ||
boot_image.program(), boot_bundle, application_bundle, argv, group_id); | ||
|
@@ -98,4 +100,3 @@ int run_program(SnapshotBundle boot_bundle, SnapshotBundle application_bundle, c | |
} | ||
|
||
} // namespace toit | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -45,6 +45,7 @@ | |
#include "heap.h" | ||
#include "process.h" | ||
#include "memory.h" | ||
#include "messaging.h" | ||
#include "embedded_data.h" | ||
#include "os.h" | ||
#include "program.h" | ||
|
@@ -113,6 +114,7 @@ static void start() { | |
{ VM vm; | ||
vm.load_platform_event_sources(); | ||
int group_id = vm.scheduler()->next_group_id(); | ||
create_and_start_external_message_handlers(&vm); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again. Do you need the group id here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done. |
||
exit_state = vm.scheduler()->run_boot_program(const_cast<Program*>(program), group_id); | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should consider just having a single
toit.h
include file that has all our APIs in there.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I called it
ctoit.h
.I think it makes sense to split it out again if we ever have more functions (and have a
ctoit.h
that combines all others). At the moment that's not worth it.done.