Skip to content

Commit

Permalink
[vm/sendports] Introduce an api that can be safely used to rebuild Se…
Browse files Browse the repository at this point in the history
…ndPort.

Existing api is not aware of origin_id, which leads to problems when a port gets closed, origin_id can't be properly restored.

Fixes #55605
TEST=vm/dart/sendport_api_test

Change-Id: Ia8a5978a968f6ea643d7921c64146cebf17d2e0e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/365120
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Alexander Aprelev <aam@google.com>
  • Loading branch information
aam authored and Commit Queue committed May 1, 2024
1 parent b026068 commit de4029e
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 1 deletion.
27 changes: 27 additions & 0 deletions runtime/include/dart_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -1522,6 +1522,10 @@ DART_EXPORT DART_WARN_UNUSED_RESULT char* Dart_IsolateMakeRunnable(
* A port is used to send or receive inter-isolate messages
*/
typedef int64_t Dart_Port;
typedef struct {
int64_t port_id;
int64_t origin_id;
} Dart_PortEx;

/**
* ILLEGAL_PORT is a port number guaranteed never to be associated with a valid
Expand Down Expand Up @@ -1773,13 +1777,27 @@ DART_EXPORT bool Dart_Post(Dart_Port port_id, Dart_Handle object);
/**
* Returns a new SendPort with the provided port id.
*
* If there is a possibility of a port closing since port_id was acquired
* for a SendPort, one should use Dart_NewSendPortEx and
* Dart_SendPortGetIdEx.
*
* \param port_id The destination port.
*
* \return A new SendPort if no errors occurs. Otherwise returns
* an error handle.
*/
DART_EXPORT Dart_Handle Dart_NewSendPort(Dart_Port port_id);

/**
* Returns a new SendPort with the provided port id and origin id.
*
* \param portex_id The destination composte port id.
*
* \return A new SendPort if no errors occurs. Otherwise returns
* an error handle.
*/
DART_EXPORT Dart_Handle Dart_NewSendPortEx(Dart_PortEx portex_id);

/**
* Gets the SendPort id for the provided SendPort.
* \param port A SendPort object whose id is desired.
Expand All @@ -1790,6 +1808,15 @@ DART_EXPORT Dart_Handle Dart_NewSendPort(Dart_Port port_id);
DART_EXPORT Dart_Handle Dart_SendPortGetId(Dart_Handle port,
Dart_Port* port_id);

/**
* Gets the SendPort and Origin ids for the provided SendPort.
* \param port A SendPort object whose id is desired.
* \param portex_id Returns composite id of the SendPort.
* \return Success if no error occurs. Otherwise returns
* an error handle.
*/
DART_EXPORT Dart_Handle Dart_SendPortGetIdEx(Dart_Handle port,
Dart_PortEx* portex_id);
/*
* ======
* Scopes
Expand Down
7 changes: 7 additions & 0 deletions runtime/include/dart_api_dl.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ DART_EXPORT intptr_t Dart_InitializeApiDL(void* data);
// are typechecked nominally in C/C++, so they are not copied, instead a
// comment is added to their definition.
typedef int64_t Dart_Port_DL;
typedef struct {
int64_t port_id;
int64_t origin_id;
} Dart_PortEx_DL;

typedef void (*Dart_NativeMessageHandler_DL)(Dart_Port_DL dest_port_id,
Dart_CObject* message);
Expand Down Expand Up @@ -94,8 +98,11 @@ typedef void (*Dart_NativeMessageHandler_DL)(Dart_Port_DL dest_port_id,
/* Dart_Port */ \
F(Dart_Post, bool, (Dart_Port_DL port_id, Dart_Handle object)) \
F(Dart_NewSendPort, Dart_Handle, (Dart_Port_DL port_id)) \
F(Dart_NewSendPortEx, Dart_Handle, (Dart_PortEx_DL portex_id)) \
F(Dart_SendPortGetId, Dart_Handle, \
(Dart_Handle port, Dart_Port_DL * port_id)) \
F(Dart_SendPortGetIdEx, Dart_Handle, \
(Dart_Handle port, Dart_PortEx_DL * portex_id)) \
/* Scopes */ \
F(Dart_EnterScope, void, (void)) \
F(Dart_ExitScope, void, (void)) \
Expand Down
2 changes: 1 addition & 1 deletion runtime/include/dart_version.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@
// On backwards compatible changes the minor version is increased.
// The versioning covers the symbols exposed in dart_api_dl.h
#define DART_API_DL_MAJOR_VERSION 2
#define DART_API_DL_MINOR_VERSION 4
#define DART_API_DL_MINOR_VERSION 5

#endif /* RUNTIME_INCLUDE_DART_VERSION_H_ */ /* NOLINT */
2 changes: 2 additions & 0 deletions runtime/tests/vm/dart/exported_symbols_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ main() {
"Dart_NewNativePort",
"Dart_NewPersistentHandle",
"Dart_NewSendPort",
"Dart_NewSendPortEx",
"Dart_NewStringFromCString",
"Dart_NewStringFromUTF16",
"Dart_NewStringFromUTF32",
Expand Down Expand Up @@ -280,6 +281,7 @@ main() {
"Dart_RunLoopAsync",
"Dart_ScopeAllocate",
"Dart_SendPortGetId",
"Dart_SendPortGetIdEx",
"Dart_ServiceSendDataEvent",
"Dart_SetBooleanReturnValue",
"Dart_SetCurrentUserTag",
Expand Down
61 changes: 61 additions & 0 deletions runtime/tests/vm/dart/sendport_api_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:isolate';
import 'dart:ffi';

import 'package:async_helper/async_helper.dart' show asyncEnd, asyncStart;
import 'package:expect/expect.dart';
import 'package:ffi/ffi.dart';

@Native<Handle Function(Int64 port)>(symbol: 'Dart_NewSendPort')
external SendPort newSendPort(int obj);

@Native<Handle Function(Handle, Pointer<Int64>)>(symbol: 'Dart_SendPortGetId')
external Object sendPortGetId(Object sendPort, Pointer<Int64> outId);

final class PortEx extends Struct {
@Int64()
external int portId;
@Int64()
external int originId;
}

@Native<Handle Function(PortEx portex)>(symbol: 'Dart_NewSendPortEx')
external SendPort newSendPortEx(PortEx portEx);

@Native<Handle Function(Handle, Pointer<PortEx>)>(
symbol: 'Dart_SendPortGetIdEx')
external Object sendPortGetIdEx(Object sendPort, Pointer<PortEx> outPortExId);

class A {}

main() async {
asyncStart();

final rp = ReceivePort();
rp.close();

{
Pointer<Int64> portId = calloc();
sendPortGetId(rp.sendPort, portId);
final sendPortThroughAPI = newSendPort(portId.value);
sendPortThroughAPI.send('A');
Expect.throwsArgumentError(() {
sendPortThroughAPI.send(A());
});
calloc.free(portId);
}

{
Pointer<PortEx> portExId = calloc();
sendPortGetIdEx(rp.sendPort, portExId);
final sendPortThroughAPI = newSendPortEx(portExId[0]);
sendPortThroughAPI.send('A');
sendPortThroughAPI.send(A());
calloc.free(portExId);
}

asyncEnd();
}
28 changes: 28 additions & 0 deletions runtime/vm/dart_api_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2157,6 +2157,17 @@ DART_EXPORT Dart_Handle Dart_NewSendPort(Dart_Port port_id) {
return Api::NewHandle(T, SendPort::New(port_id, origin_id));
}

DART_EXPORT Dart_Handle Dart_NewSendPortEx(Dart_PortEx portex_id) {
DARTSCOPE(Thread::Current());
CHECK_CALLBACK_STATE(T);
if (portex_id.port_id == ILLEGAL_PORT) {
return Api::NewError("%s: illegal port_id %" Pd64 ".", CURRENT_FUNC,
portex_id.port_id);
}
return Api::NewHandle(T,
SendPort::New(portex_id.port_id, portex_id.origin_id));
}

DART_EXPORT Dart_Handle Dart_SendPortGetId(Dart_Handle port,
Dart_Port* port_id) {
DARTSCOPE(Thread::Current());
Expand All @@ -2173,6 +2184,23 @@ DART_EXPORT Dart_Handle Dart_SendPortGetId(Dart_Handle port,
return Api::Success();
}

DART_EXPORT Dart_Handle Dart_SendPortGetIdEx(Dart_Handle port,
Dart_PortEx* portex_id) {
DARTSCOPE(Thread::Current());
CHECK_CALLBACK_STATE(T);
API_TIMELINE_DURATION(T);
const SendPort& send_port = Api::UnwrapSendPortHandle(Z, port);
if (send_port.IsNull()) {
RETURN_TYPE_ERROR(Z, port, SendPort);
}
if (portex_id == nullptr) {
RETURN_NULL_ERROR(port_id);
}
portex_id->port_id = send_port.Id();
portex_id->origin_id = send_port.origin_id();
return Api::Success();
}

DART_EXPORT Dart_Port Dart_GetMainPortId() {
Isolate* isolate = Isolate::Current();
CHECK_ISOLATE(isolate);
Expand Down

0 comments on commit de4029e

Please sign in to comment.