From 26efd800b0a3edabe1ca7c8299bc80ffa0f9f65b Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 9 Nov 2023 22:05:07 -0800 Subject: [PATCH 1/8] Fix protobufs path problem --- .../federated/extensions/CExtension.java | 14 +++++-- .../org/lflang/generator/c/CGenerator.java | 38 ++++++++++-------- .../generator/python/PythonGenerator.java | 39 +++++++++---------- 3 files changed, 50 insertions(+), 41 deletions(-) diff --git a/core/src/main/java/org/lflang/federated/extensions/CExtension.java b/core/src/main/java/org/lflang/federated/extensions/CExtension.java index 29039010b4..3b8eae6ed0 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtension.java @@ -189,8 +189,11 @@ protected void deserialize( result.pr("lf_set(" + receiveRef + ", " + value + ");"); } } - case PROTO -> throw new UnsupportedOperationException( - "Protobuf serialization is not supported yet."); + case PROTO -> { + return; + } + // throw new UnsupportedOperationException( + // "Protobuf serialization is not supported yet."); case ROS2 -> { var portType = ASTUtils.getInferredType(((Port) receivingPort.getVariable())); var portTypeStr = types.getTargetType(portType); @@ -408,8 +411,11 @@ protected void serializeAndSend( result.pr(sendingFunction + "(" + commonArgs + ", " + pointerExpression + ");"); } } - case PROTO -> throw new UnsupportedOperationException( - "Protobuf serialization is not supported yet."); + case PROTO -> { + return; + } + // throw new UnsupportedOperationException( + // "Protobuf serialization is not supported yet."); case ROS2 -> { var typeStr = types.getTargetType(type); if (CUtil.isTokenType(type, types)) { diff --git a/core/src/main/java/org/lflang/generator/c/CGenerator.java b/core/src/main/java/org/lflang/generator/c/CGenerator.java index b02c2ed5b0..2b232b47d3 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -34,7 +34,6 @@ import static org.lflang.ast.ASTUtils.toText; import static org.lflang.util.StringUtil.addDoubleQuotes; -import com.google.common.base.Objects; import com.google.common.collect.Iterables; import java.io.File; import java.io.IOException; @@ -45,6 +44,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -1452,7 +1452,7 @@ private void generateStartTimeStep(ReactorInstance instance) { temp.pr("// Add port " + port.getFullName() + " to array of is_present fields."); - if (!Objects.equal(port.getParent(), instance)) { + if (!port.getParent().equals(instance)) { // The port belongs to contained reactor, so we also have // iterate over the instance bank members. temp.startScopedBlock(); @@ -1486,7 +1486,7 @@ private void generateStartTimeStep(ReactorInstance instance) { enclaveInfo.numIsPresentFields += port.getWidth() * port.getParent().getTotalWidth(); - if (!Objects.equal(port.getParent(), instance)) { + if (!port.getParent().equals(instance)) { temp.pr("count++;"); temp.endScopedBlock(); temp.endScopedBlock(); @@ -1614,25 +1614,31 @@ private void generateTimerInitializations(ReactorInstance instance) { *

Run, if possible, the proto-c protocol buffer code generator to produce the required .h and * .c files. * - * @param filename Name of the file to process. + * @param file Path of the .proto file to process. */ - public void processProtoFile(String filename) { + public void processProtoFile(Path file) { + var fileName = file.getFileName().toString(); + var directory = Objects.requireNonNullElse(file.getParent(), ""); var protoc = commandFactory.createCommand( "protoc-c", - List.of("--c_out=" + this.fileConfig.getSrcGenPath(), filename), + List.of( + "--c_out=" + this.fileConfig.getSrcGenPath(), + "--proto_path=" + directory, + fileName), fileConfig.srcPath); if (protoc == null) { messageReporter.nowhere().error("Processing .proto files requires protoc-c >= 1.3.3."); - return; - } - var returnCode = protoc.run(); - if (returnCode == 0) { - var nameSansProto = filename.substring(0, filename.length() - 6); - targetConfig.compileAdditionalSources.add( - fileConfig.getSrcGenPath().resolve(nameSansProto + ".pb-c.c").toString()); } else { - messageReporter.nowhere().error("protoc-c returns error code " + returnCode); + var returnCode = protoc.run(); + if (returnCode == 0) { + messageReporter.nowhere().info("Successfully compiled " + file); + var nameSansProto = fileName.substring(0, fileName.length() - 6); + targetConfig.compileAdditionalSources.add( + fileConfig.getSrcGenPath().resolve(nameSansProto + ".pb-c.c").toString()); + } else { + messageReporter.nowhere().error("protoc-c failed:" + protoc.getErrors()); + } } } @@ -2013,10 +2019,10 @@ protected void setUpGeneralParameters() { } } + /** Iterate over the .proto files specified in the 'proto' target property and compile them. */ protected void handleProtoFiles() { - // Handle .proto files. for (String file : targetConfig.get(ProtobufsProperty.INSTANCE)) { - this.processProtoFile(file); + this.processProtoFile(Path.of(file)); } } diff --git a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java index e4477d2d0d..1189a8ba4b 100644 --- a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java +++ b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java @@ -31,6 +31,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -63,7 +64,6 @@ import org.lflang.target.property.CompilerProperty; import org.lflang.target.property.ProtobufsProperty; import org.lflang.util.FileUtil; -import org.lflang.util.LFCommand; import org.lflang.util.StringUtil; /** @@ -280,7 +280,7 @@ protected String generateTopLevelPreambles(Reactor ignored) { @Override protected void handleProtoFiles() { for (String name : targetConfig.get(ProtobufsProperty.INSTANCE)) { - this.processProtoFile(name); + this.processProtoFile(Path.of(name)); int dotIndex = name.lastIndexOf("."); String rootFilename = dotIndex > 0 ? name.substring(0, dotIndex) : name; pythonPreamble.pr("import " + rootFilename + "_pb2 as " + rootFilename); @@ -288,31 +288,28 @@ protected void handleProtoFiles() { } } - /** - * Process a given .proto file. - * - *

Run, if possible, the proto-c protocol buffer code generator to produce the required .h and - * .c files. - * - * @param filename Name of the file to process. - */ @Override - public void processProtoFile(String filename) { - LFCommand protoc = + public void processProtoFile(Path file) { + var fileName = file.getFileName().toString(); + var directory = Objects.requireNonNullElse(file.getParent(), ""); + var protoc = commandFactory.createCommand( "protoc", - List.of("--python_out=" + fileConfig.getSrcGenPath(), filename), + List.of( + "--python_out=" + this.fileConfig.getSrcGenPath(), + "--proto_path=" + directory, + fileName), fileConfig.srcPath); - if (protoc == null) { - messageReporter.nowhere().error("Processing .proto files requires libprotoc >= 3.6.1"); - return; - } - int returnCode = protoc.run(); - if (returnCode == 0) { - pythonRequiredModules.add("google-api-python-client"); + messageReporter.nowhere().error("Processing .proto files requires protoc-c >= 1.3.3."); } else { - messageReporter.nowhere().error("protoc returns error code " + returnCode); + var returnCode = protoc.run(); + if (returnCode == 0) { + messageReporter.nowhere().info("Successfully compiled " + file); + pythonRequiredModules.add("google-api-python-client"); + } else { + messageReporter.nowhere().error("protoc-c failed:" + protoc.getErrors()); + } } } From 5ffafd3b8f3c932971e37263ce9cc7fb1b9d7f93 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 9 Nov 2023 23:11:08 -0800 Subject: [PATCH 2/8] Fix one more path problem --- core/src/main/java/org/lflang/generator/c/CGenerator.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/lflang/generator/c/CGenerator.java b/core/src/main/java/org/lflang/generator/c/CGenerator.java index 2b232b47d3..d6f0202371 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -2053,10 +2053,11 @@ protected String generateTopLevelPreambles(Reactor reactor) { .collect(Collectors.toSet()) .forEach(it -> builder.pr(toText(it.getCode()))); for (String file : targetConfig.get(ProtobufsProperty.INSTANCE)) { - var dotIndex = file.lastIndexOf("."); + var fileName = Path.of(file).getFileName().toString(); + var dotIndex = fileName.lastIndexOf("."); var rootFilename = file; if (dotIndex > 0) { - rootFilename = file.substring(0, dotIndex); + rootFilename = fileName.substring(0, dotIndex); } code.pr("#include " + addDoubleQuotes(rootFilename + ".pb-c.h")); builder.pr("#include " + addDoubleQuotes(rootFilename + ".pb-c.h")); From 4082f4e8dda1f2d3201ed9f08782d3ac25a8751f Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 10 Nov 2023 10:39:27 -0800 Subject: [PATCH 3/8] Updated protobufs setup instructions --- test/C/src/serialization/PersonProtocolBuffers.lf | 14 +++++++------- test/C/src/serialization/ProtoNoPacking.lf | 13 +++++++------ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/test/C/src/serialization/PersonProtocolBuffers.lf b/test/C/src/serialization/PersonProtocolBuffers.lf index 193de9193a..6f30370d38 100644 --- a/test/C/src/serialization/PersonProtocolBuffers.lf +++ b/test/C/src/serialization/PersonProtocolBuffers.lf @@ -9,13 +9,13 @@ * * $ brew install protobuf * - * Building protobuf from source is slow, so avoid doing that if possible. Next install the C plugin - * for protocol buffers from - * - * https://github.com/protobuf-c/protobuf-c - * - * The code generator assumes that executables are installed within the PATH. On a Mac, this is - * typically at /usr/local/bin. + * (Building protobuf from source is slow, so avoid doing that if possible.) + * + * Next install the C plugin for protocol buffers: + * + * $ brew install protobuf-c + * + * This comes from https://github.com/protobuf-c/protobuf-c. */ target C { protobufs: Person.proto diff --git a/test/C/src/serialization/ProtoNoPacking.lf b/test/C/src/serialization/ProtoNoPacking.lf index 57b610e337..25b6fd1b66 100644 --- a/test/C/src/serialization/ProtoNoPacking.lf +++ b/test/C/src/serialization/ProtoNoPacking.lf @@ -8,13 +8,14 @@ * * $ brew install protobuf * - * Building protobuf from source is slow, so avoid doing that if possible. Next install the C plugin - * for protocol buffers from + * (Building protobuf from source is slow, so avoid doing that if possible.) + * + * Next install the C plugin for protocol buffers: + * + * $ brew install protobuf-c + * + * This comes from https://github.com/protobuf-c/protobuf-c. * - * https://github.com/protobuf-c/protobuf-c - * - * The code generator assumes that executables are installed within the PATH. On a Mac, this is - * typically at /usr/local/bin. */ target C { protobufs: [ProtoHelloWorld.proto] From 2e3bef9eb94c3a861054e07af713ce5bdc5a4983 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 12 Nov 2023 23:12:50 -0800 Subject: [PATCH 4/8] Fix comments --- .../C/src/serialization/PersonProtocolBuffers.lf | 15 ++++++--------- test/C/src/serialization/ProtoNoPacking.lf | 16 ++++++---------- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/test/C/src/serialization/PersonProtocolBuffers.lf b/test/C/src/serialization/PersonProtocolBuffers.lf index 6f30370d38..aa312ebabf 100644 --- a/test/C/src/serialization/PersonProtocolBuffers.lf +++ b/test/C/src/serialization/PersonProtocolBuffers.lf @@ -4,18 +4,15 @@ * on the examples at https://github.com/protobuf-c/protobuf-c/wiki/Examples. This example just * packs and unpacks a message. * - * To run this example first install the protocol buffers compiler from - * https://github.com/protocolbuffers/protobuf. It is also available from homebrew on a Mac via - * - * $ brew install protobuf + * To run this test, first install the protocol buffers compiler from + * https://github.com/protocolbuffers/protobuf as well as the C plugin which comes from + * https://github.com/protobuf-c/protobuf-c. * * (Building protobuf from source is slow, so avoid doing that if possible.) - * - * Next install the C plugin for protocol buffers: - * + * + * On Mac, you can install these dependencies via Homebrew: + * $ brew install protobuf * $ brew install protobuf-c - * - * This comes from https://github.com/protobuf-c/protobuf-c. */ target C { protobufs: Person.proto diff --git a/test/C/src/serialization/ProtoNoPacking.lf b/test/C/src/serialization/ProtoNoPacking.lf index 25b6fd1b66..c889f78f99 100644 --- a/test/C/src/serialization/ProtoNoPacking.lf +++ b/test/C/src/serialization/ProtoNoPacking.lf @@ -3,19 +3,15 @@ * and unpacking. This demonstrates that local communication, within one shared-memory machine, need * not incur the overhead of packing and unpacking. * - * To run this example first install the protocol buffers compiler from - * https://github.com/protocolbuffers/protobuf. It is also available from homebrew on a Mac via - * - * $ brew install protobuf + * To run this test, first install the protocol buffers compiler from + * https://github.com/protocolbuffers/protobuf as well as the C plugin which comes from + * https://github.com/protobuf-c/protobuf-c. * * (Building protobuf from source is slow, so avoid doing that if possible.) - * - * Next install the C plugin for protocol buffers: - * - * $ brew install protobuf-c - * - * This comes from https://github.com/protobuf-c/protobuf-c. * + * On Mac, you can install these dependencies via Homebrew: + * $ brew install protobuf + * $ brew install protobuf-c */ target C { protobufs: [ProtoHelloWorld.proto] From b1bb2d60eee704725c9dceb1a45ac4ca08d53d70 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 29 Nov 2023 13:05:49 -0800 Subject: [PATCH 5/8] Added failing ProtoNoPackingFederated test --- .../serialization/ProtoNoPackingFederated.lf | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 test/C/src/serialization/ProtoNoPackingFederated.lf diff --git a/test/C/src/serialization/ProtoNoPackingFederated.lf b/test/C/src/serialization/ProtoNoPackingFederated.lf new file mode 100644 index 0000000000..8b8ff2cecc --- /dev/null +++ b/test/C/src/serialization/ProtoNoPackingFederated.lf @@ -0,0 +1,46 @@ +/** + * This example creates a Protocol Buffer message and passes it to another reactor without packing + * and unpacking. This demonstrates that local communication, within one shared-memory machine, need + * not incur the overhead of packing and unpacking. + * + * To run this example first install the protocol buffers compiler from + * https://github.com/protocolbuffers/protobuf. It is also available from homebrew on a Mac via + * + * $ brew install protobuf + * + * Building protobuf from source is slow, so avoid doing that if possible. Next install the C plugin + * for protocol buffers from + * + * https://github.com/protobuf-c/protobuf-c + * + * The code generator assumes that executables are installed within the PATH. On a Mac, this is + * typically at /usr/local/bin. + */ +target C { + protobufs: [ProtoHelloWorld.proto], + timeout: 1 s +} + +reactor SourceProto { + output out: ProtoHelloWorld + + reaction(startup) -> out {= + out->value.name = "Hello World"; + out->value.number = 42; + SET_PRESENT(out); + =} +} + +reactor SinkProto { + input in: ProtoHelloWorld + + reaction(in) {= + printf("Received: name=\"%s\", number=%d.\n", in->value.name, in->value.number); + =} +} + +federated reactor { + s = new SourceProto() + d = new SinkProto() + s.out -> d.in +} From 80c865f2160dc8fae858999d3f2bacc6c253cb26 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Thu, 30 Nov 2023 12:12:29 -0800 Subject: [PATCH 6/8] Template for federate protobufs compiles. Message is incomplete --- .../federated/extensions/CExtension.java | 23 ++++- .../{ProtoHelloWorld.proto => Hello.proto} | 3 +- .../serialization/PersonProtocolBuffers.lf | 1 + test/C/src/serialization/ProtoFederated.lf | 91 +++++++++++++++++++ test/C/src/serialization/ProtoNoPacking.lf | 6 +- .../serialization/ProtoNoPackingFederated.lf | 46 ---------- 6 files changed, 115 insertions(+), 55 deletions(-) rename test/C/src/serialization/{ProtoHelloWorld.proto => Hello.proto} (63%) create mode 100644 test/C/src/serialization/ProtoFederated.lf delete mode 100644 test/C/src/serialization/ProtoNoPackingFederated.lf diff --git a/core/src/main/java/org/lflang/federated/extensions/CExtension.java b/core/src/main/java/org/lflang/federated/extensions/CExtension.java index 3b8eae6ed0..df29832605 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtension.java @@ -190,10 +190,18 @@ protected void deserialize( } } case PROTO -> { - return; + // In C, the type of the action is uint8*, so it will be a token type. + value = action.getName() + "->value"; + var length = action.getName() + "->length"; + var portType = types.getTargetType(ASTUtils.getInferredType(((Port) receivingPort.getVariable()))); + var prefix = portType.toLowerCase().replace("*", ""); + // FIXME: Protobufs does weird things converting cammel case to snake case and vice versa. + // The following "toLowerCase()" call will only work for single-word types. + result.pr(portType + " unpacked = " + prefix + "__unpack(NULL, " + length + ", " + value + ");"); + // FIXME: Should generate and set destructor and copy constructor for this type. + // See: https://www.lf-lang.org/docs/handbook/target-language-details?target=c#dynamically-allocated-data + result.pr("lf_set(" + receiveRef + ", unpacked);"); } - // throw new UnsupportedOperationException( - // "Protobuf serialization is not supported yet."); case ROS2 -> { var portType = ASTUtils.getInferredType(((Port) receivingPort.getVariable())); var portTypeStr = types.getTargetType(portType); @@ -412,7 +420,14 @@ protected void serializeAndSend( } } case PROTO -> { - return; + // FIXME: Protobufs does weird things converting camel case to snake case and vice versa. + // The following "toLowerCase()" call will only work for single-word types. + var targetType = types.getTargetType(type).toLowerCase(); + var prefix = targetType.replace("*", ""); + result.pr("size_t _lf_message_length = " + prefix + "__get_packed_size(" + sendRef + "->value);"); + result.pr("uint8_t* buffer = (uint8_t*)malloc(_lf_message_length);"); + result.pr(prefix + "__pack(" + sendRef + "->value, buffer);"); + result.pr(sendingFunction + "(" + commonArgs + ", buffer);"); } // throw new UnsupportedOperationException( // "Protobuf serialization is not supported yet."); diff --git a/test/C/src/serialization/ProtoHelloWorld.proto b/test/C/src/serialization/Hello.proto similarity index 63% rename from test/C/src/serialization/ProtoHelloWorld.proto rename to test/C/src/serialization/Hello.proto index 22f7b6dedd..71883f35e0 100644 --- a/test/C/src/serialization/ProtoHelloWorld.proto +++ b/test/C/src/serialization/Hello.proto @@ -2,8 +2,7 @@ syntax = "proto3"; -message ProtoHelloWorld { +message Hello { string name = 1; int32 number = 2; - repeated string sentence = 3; } diff --git a/test/C/src/serialization/PersonProtocolBuffers.lf b/test/C/src/serialization/PersonProtocolBuffers.lf index aa312ebabf..f4dc391b9f 100644 --- a/test/C/src/serialization/PersonProtocolBuffers.lf +++ b/test/C/src/serialization/PersonProtocolBuffers.lf @@ -29,6 +29,7 @@ main reactor { person.email = "eal@berkeley.edu"; // Pack the message into buffer. + person__init(&person); len = person__get_packed_size(&person); buffer = (uint8_t*)malloc(len); person__pack(&person, buffer); diff --git a/test/C/src/serialization/ProtoFederated.lf b/test/C/src/serialization/ProtoFederated.lf new file mode 100644 index 0000000000..f08e03a404 --- /dev/null +++ b/test/C/src/serialization/ProtoFederated.lf @@ -0,0 +1,91 @@ +/** + * This example creates a Protocol Buffer message and passes it to another reactor without packing + * and unpacking. This demonstrates that local communication, within one shared-memory machine, need + * not incur the overhead of packing and unpacking. + * + * To run this example first install the protocol buffers compiler from + * https://github.com/protocolbuffers/protobuf. It is also available from homebrew on a Mac via + * + * $ brew install protobuf + * + * Building protobuf from source is slow, so avoid doing that if possible. Next install the C plugin + * for protocol buffers from + * + * https://github.com/protobuf-c/protobuf-c + * + * The code generator assumes that executables are installed within the PATH. On a Mac, this is + * typically at /usr/local/bin. + */ +target C { + protobufs: [Hello.proto], + timeout: 1 s +} + +reactor BaseProto { + preamble {= + // FIXME: Ideally, these functions would be generated by the tool + // processing the .proto file. + #include + + Hello* hello_constructor(char* name, int32_t number) { + Hello* result = (Hello*)malloc(sizeof(Hello)); + hello__init(result); + // Copy the string into dynamically allocated memory. + char* name_copy = (char*)malloc(strlen(name) + 1); + if (name_copy == NULL) lf_print_error_and_exit("Out of memory."); + strcpy(name_copy, name); + result->name = name_copy; + result->number = number; + return result; + } + // Destructor as required by + // https://www.lf-lang.org/docs/handbook/target-language-details?target=c#dynamically-allocated-data + // This destructor is to be used if the Hello object is constructed using the hello_constructor + // or the copy constructor. + // If the Hello object is unpacked (i.e. at the receiving end), then it should be freed with + // hello_unpacked_destructor(). + void hello_destructor(void* hello) { + Hello* cast = (Hello*)hello; + free(cast->name); + free(cast); + } + // Destructor to use at the receiving end, which frees the memory used to unpack the message. + void hello_unpacked_destructor(void* hello) { + Hello* cast = (Hello*)hello; + hello__free_unpacked(cast, NULL); + } + // FIXME: Should also provide a copy constructor. + =} +} + +reactor SourceProto extends BaseProto { + output out: Hello* + + reaction(startup) -> out {= + // The output port needs to be associated with a destructor to + // free the memory we are allocating here. + // See https://github.com/lf-lang/lingua-franca/issues/2121 + lf_set_destructor(out, hello_destructor); + // Don't really need a copy constructor here because it will not be used. + Hello* value = hello_constructor("Hello World", 42); + lf_set(out, value); + =} +} + +reactor SinkProto extends BaseProto { + input in: Hello* + + reaction(startup) in {= + // FIXME: Ideally, this would be automatically generated. + lf_set_destructor(in, hello_unpacked_destructor); + =} + reaction(in) {= + printf("Received: name=\"%s\", number=%d.\n", in->value->name, in->value->number); + =} +} + +federated reactor { + s = new SourceProto() + d = new SinkProto() + s.out -> d.in serializer "proto" +} diff --git a/test/C/src/serialization/ProtoNoPacking.lf b/test/C/src/serialization/ProtoNoPacking.lf index c889f78f99..8a00efeb6a 100644 --- a/test/C/src/serialization/ProtoNoPacking.lf +++ b/test/C/src/serialization/ProtoNoPacking.lf @@ -14,11 +14,11 @@ * $ brew install protobuf-c */ target C { - protobufs: [ProtoHelloWorld.proto] + protobufs: [Hello.proto] } reactor SourceProto { - output out: ProtoHelloWorld + output out: Hello reaction(startup) -> out {= out->value.name = "Hello World"; @@ -28,7 +28,7 @@ reactor SourceProto { } reactor SinkProto { - input in: ProtoHelloWorld + input in: Hello reaction(in) {= printf("Received: name=\"%s\", number=%d.\n", in->value.name, in->value.number); diff --git a/test/C/src/serialization/ProtoNoPackingFederated.lf b/test/C/src/serialization/ProtoNoPackingFederated.lf deleted file mode 100644 index 8b8ff2cecc..0000000000 --- a/test/C/src/serialization/ProtoNoPackingFederated.lf +++ /dev/null @@ -1,46 +0,0 @@ -/** - * This example creates a Protocol Buffer message and passes it to another reactor without packing - * and unpacking. This demonstrates that local communication, within one shared-memory machine, need - * not incur the overhead of packing and unpacking. - * - * To run this example first install the protocol buffers compiler from - * https://github.com/protocolbuffers/protobuf. It is also available from homebrew on a Mac via - * - * $ brew install protobuf - * - * Building protobuf from source is slow, so avoid doing that if possible. Next install the C plugin - * for protocol buffers from - * - * https://github.com/protobuf-c/protobuf-c - * - * The code generator assumes that executables are installed within the PATH. On a Mac, this is - * typically at /usr/local/bin. - */ -target C { - protobufs: [ProtoHelloWorld.proto], - timeout: 1 s -} - -reactor SourceProto { - output out: ProtoHelloWorld - - reaction(startup) -> out {= - out->value.name = "Hello World"; - out->value.number = 42; - SET_PRESENT(out); - =} -} - -reactor SinkProto { - input in: ProtoHelloWorld - - reaction(in) {= - printf("Received: name=\"%s\", number=%d.\n", in->value.name, in->value.number); - =} -} - -federated reactor { - s = new SourceProto() - d = new SinkProto() - s.out -> d.in -} From 5a2d6ae4296cbc33669071c00087a907c725c33d Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Thu, 30 Nov 2023 16:43:57 -0800 Subject: [PATCH 7/8] Fix bug: set length on incoming token --- .../main/java/org/lflang/generator/c/CReactionGenerator.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/src/main/java/org/lflang/generator/c/CReactionGenerator.java b/core/src/main/java/org/lflang/generator/c/CReactionGenerator.java index 2a9219983a..551fe5a026 100644 --- a/core/src/main/java/org/lflang/generator/c/CReactionGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CReactionGenerator.java @@ -584,6 +584,11 @@ private static String generateActionVariablesInReaction( + ")" + tokenPointer + "->value;"); + builder.pr( + action.getName() + + "->length = " + + tokenPointer + + "->length;"); } else { builder.pr( action.getName() From c205cfaafaece9b4175ae2a6082ed25a41e6cd71 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Thu, 30 Nov 2023 17:00:48 -0800 Subject: [PATCH 8/8] Simplified to not require a destructor at the sender --- test/C/src/serialization/ProtoFederated.lf | 56 ++++++---------------- 1 file changed, 14 insertions(+), 42 deletions(-) diff --git a/test/C/src/serialization/ProtoFederated.lf b/test/C/src/serialization/ProtoFederated.lf index f08e03a404..40285da7a4 100644 --- a/test/C/src/serialization/ProtoFederated.lf +++ b/test/C/src/serialization/ProtoFederated.lf @@ -21,34 +21,22 @@ target C { timeout: 1 s } -reactor BaseProto { +reactor SourceProto { + output out: Hello* + + reaction(startup) -> out {= + Hello* value = (Hello*)malloc(sizeof(Hello)); + hello__init(value); + value->name = "Hello World"; + value->number = 42; + lf_set(out, value); + =} +} + +reactor SinkProto { preamble {= - // FIXME: Ideally, these functions would be generated by the tool + // FIXME: Ideally, this function would be generated by the tool // processing the .proto file. - #include - - Hello* hello_constructor(char* name, int32_t number) { - Hello* result = (Hello*)malloc(sizeof(Hello)); - hello__init(result); - // Copy the string into dynamically allocated memory. - char* name_copy = (char*)malloc(strlen(name) + 1); - if (name_copy == NULL) lf_print_error_and_exit("Out of memory."); - strcpy(name_copy, name); - result->name = name_copy; - result->number = number; - return result; - } - // Destructor as required by - // https://www.lf-lang.org/docs/handbook/target-language-details?target=c#dynamically-allocated-data - // This destructor is to be used if the Hello object is constructed using the hello_constructor - // or the copy constructor. - // If the Hello object is unpacked (i.e. at the receiving end), then it should be freed with - // hello_unpacked_destructor(). - void hello_destructor(void* hello) { - Hello* cast = (Hello*)hello; - free(cast->name); - free(cast); - } // Destructor to use at the receiving end, which frees the memory used to unpack the message. void hello_unpacked_destructor(void* hello) { Hello* cast = (Hello*)hello; @@ -56,23 +44,7 @@ reactor BaseProto { } // FIXME: Should also provide a copy constructor. =} -} - -reactor SourceProto extends BaseProto { - output out: Hello* - - reaction(startup) -> out {= - // The output port needs to be associated with a destructor to - // free the memory we are allocating here. - // See https://github.com/lf-lang/lingua-franca/issues/2121 - lf_set_destructor(out, hello_destructor); - // Don't really need a copy constructor here because it will not be used. - Hello* value = hello_constructor("Hello World", 42); - lf_set(out, value); - =} -} -reactor SinkProto extends BaseProto { input in: Hello* reaction(startup) in {=