mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 14:32:24 +00:00
- Implement some more missing pieces of the Isolate API.
Added: * addOnExitListener, removeOnExitListener * setErrorsFatal * addOnErrorListener, removeOnErrorListener R=asiva@google.com Review URL: https://codereview.chromium.org//881373002 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@44307 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
parent
87790063a4
commit
91e105d8c6
8 changed files with 290 additions and 22 deletions
|
@ -335,6 +335,11 @@ patch class Isolate {
|
|||
static const _RESUME = 2;
|
||||
static const _PING = 3;
|
||||
static const _KILL = 4;
|
||||
static const _ADD_EXIT = 5;
|
||||
static const _DEL_EXIT = 6;
|
||||
static const _ADD_ERROR = 7;
|
||||
static const _DEL_ERROR = 8;
|
||||
static const _ERROR_FATAL = 9;
|
||||
|
||||
|
||||
static void _spawnFunction(SendPort readyPort, Function topLevelFunction,
|
||||
|
@ -367,15 +372,28 @@ patch class Isolate {
|
|||
}
|
||||
|
||||
/* patch */ void addOnExitListener(SendPort responsePort) {
|
||||
throw new UnsupportedError("addOnExitListener");
|
||||
var msg = new List(3)
|
||||
..[0] = 0 // Make room for OOB message type.
|
||||
..[1] = _ADD_EXIT
|
||||
..[2] = responsePort;
|
||||
_sendOOB(controlPort, msg);
|
||||
}
|
||||
|
||||
/* patch */ void removeOnExitListener(SendPort responsePort) {
|
||||
throw new UnsupportedError("removeOnExitListener");
|
||||
var msg = new List(3)
|
||||
..[0] = 0 // Make room for OOB message type.
|
||||
..[1] = _DEL_EXIT
|
||||
..[2] = responsePort;
|
||||
_sendOOB(controlPort, msg);
|
||||
}
|
||||
|
||||
/* patch */ void setErrorsFatal(bool errorsAreFatal) {
|
||||
throw new UnsupportedError("setErrorsFatal");
|
||||
var msg = new List(4)
|
||||
..[0] = 0 // Make room for OOB message type.
|
||||
..[1] = _ERROR_FATAL
|
||||
..[2] = terminateCapability
|
||||
..[3] = errorsAreFatal;
|
||||
_sendOOB(controlPort, msg);
|
||||
}
|
||||
|
||||
/* patch */ void kill([int priority = BEFORE_NEXT_EVENT]) {
|
||||
|
@ -397,11 +415,19 @@ patch class Isolate {
|
|||
}
|
||||
|
||||
/* patch */ void addErrorListener(SendPort port) {
|
||||
throw new UnsupportedError("addErrorListener");
|
||||
var msg = new List(3)
|
||||
..[0] = 0 // Make room for OOB message type.
|
||||
..[1] = _ADD_ERROR
|
||||
..[2] = port;
|
||||
_sendOOB(controlPort, msg);
|
||||
}
|
||||
|
||||
/* patch */ void removeErrorListener(SendPort port) {
|
||||
throw new UnsupportedError("removeErrorListener");
|
||||
var msg = new List(3)
|
||||
..[0] = 0 // Make room for OOB message type.
|
||||
..[1] = _DEL_ERROR
|
||||
..[2] = port;
|
||||
_sendOOB(controlPort, msg);
|
||||
}
|
||||
|
||||
static Isolate _getCurrentIsolate() {
|
||||
|
|
|
@ -126,13 +126,21 @@ class IsolateMessageHandler : public MessageHandler {
|
|||
virtual Isolate* isolate() const { return isolate_; }
|
||||
|
||||
private:
|
||||
// Keep in sync with isolate_patch.dart.
|
||||
// Keep both these enums in sync with isolate_patch.dart.
|
||||
// The different Isolate API message types.
|
||||
enum {
|
||||
kPauseMsg = 1,
|
||||
kResumeMsg = 2,
|
||||
kPingMsg = 3,
|
||||
kKillMsg = 4,
|
||||
|
||||
kAddExitMsg = 5,
|
||||
kDelExitMsg = 6,
|
||||
kAddErrorMsg = 7,
|
||||
kDelErrorMsg = 8,
|
||||
kErrorFatalMsg = 9,
|
||||
};
|
||||
// The different Isolate API message priorities for ping and kill messages.
|
||||
enum {
|
||||
kImmediateAction = 0,
|
||||
kBeforeNextEventAction = 1,
|
||||
kAsEventAction = 2
|
||||
|
@ -167,8 +175,8 @@ bool IsolateMessageHandler::HandleLibMessage(const Array& message) {
|
|||
if (message.Length() < 2) return true;
|
||||
const Object& type = Object::Handle(I, message.At(1));
|
||||
if (!type.IsSmi()) return true;
|
||||
const Smi& msg_type = Smi::Cast(type);
|
||||
switch (msg_type.Value()) {
|
||||
const intptr_t msg_type = Smi::Cast(type).Value();
|
||||
switch (msg_type) {
|
||||
case kPauseMsg: {
|
||||
// [ OOB, kPauseMsg, pause capability, resume capability ]
|
||||
if (message.Length() != 4) return true;
|
||||
|
@ -255,6 +263,45 @@ bool IsolateMessageHandler::HandleLibMessage(const Array& message) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case kAddExitMsg:
|
||||
case kDelExitMsg:
|
||||
case kAddErrorMsg:
|
||||
case kDelErrorMsg: {
|
||||
// [ OOB, msg, listener port ]
|
||||
if (message.Length() != 3) return true;
|
||||
const Object& obj = Object::Handle(I, message.At(2));
|
||||
if (!obj.IsSendPort()) return true;
|
||||
const SendPort& listener = SendPort::Cast(obj);
|
||||
switch (msg_type) {
|
||||
case kAddExitMsg:
|
||||
I->AddExitListener(listener);
|
||||
break;
|
||||
case kDelExitMsg:
|
||||
I->RemoveExitListener(listener);
|
||||
break;
|
||||
case kAddErrorMsg:
|
||||
I->AddErrorListener(listener);
|
||||
break;
|
||||
case kDelErrorMsg:
|
||||
I->RemoveErrorListener(listener);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kErrorFatalMsg: {
|
||||
// [ OOB, kErrorFatalMsg, terminate capability, val ]
|
||||
if (message.Length() != 4) return true;
|
||||
// Check that the terminate capability has been passed correctly.
|
||||
Object& obj = Object::Handle(I, message.At(2));
|
||||
if (!I->VerifyTerminateCapability(obj)) return true;
|
||||
// Get the value to be set.
|
||||
obj = message.At(3);
|
||||
if (!obj.IsBool()) return true;
|
||||
I->SetErrorsFatal(Bool::Cast(obj).value());
|
||||
break;
|
||||
}
|
||||
#if defined(DEBUG)
|
||||
// Malformed OOB messages are silently ignored in release builds.
|
||||
default:
|
||||
|
@ -438,8 +485,35 @@ bool IsolateMessageHandler::ProcessUnhandledException(const Error& result) {
|
|||
Dart_ExitScope();
|
||||
}
|
||||
|
||||
I->object_store()->set_sticky_error(result);
|
||||
return false;
|
||||
// Generate the error and stacktrace strings for the error message.
|
||||
String& exc_str = String::Handle(I);
|
||||
String& stacktrace_str = String::Handle(I);
|
||||
if (result.IsUnhandledException()) {
|
||||
const UnhandledException& uhe = UnhandledException::Cast(result);
|
||||
const Instance& exception = Instance::Handle(I, uhe.exception());
|
||||
Object& tmp = Object::Handle(I);
|
||||
tmp = DartLibraryCalls::ToString(exception);
|
||||
if (!tmp.IsString()) {
|
||||
tmp = String::New(exception.ToCString());
|
||||
}
|
||||
exc_str ^= tmp.raw();
|
||||
|
||||
const Instance& stacktrace = Instance::Handle(I, uhe.stacktrace());
|
||||
tmp = DartLibraryCalls::ToString(stacktrace);
|
||||
if (!tmp.IsString()) {
|
||||
tmp = String::New(stacktrace.ToCString());
|
||||
}
|
||||
stacktrace_str ^= tmp.raw();;
|
||||
} else {
|
||||
exc_str = String::New(result.ToErrorCString());
|
||||
}
|
||||
I->NotifyErrorListeners(exc_str, stacktrace_str);
|
||||
|
||||
if (I->ErrorsFatal()) {
|
||||
I->object_store()->set_sticky_error(result);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -470,6 +544,7 @@ Isolate::Isolate()
|
|||
origin_id_(0),
|
||||
pause_capability_(0),
|
||||
terminate_capability_(0),
|
||||
errors_fatal_(true),
|
||||
heap_(NULL),
|
||||
object_store_(NULL),
|
||||
top_exit_frame_info_(0),
|
||||
|
@ -535,6 +610,7 @@ Isolate::Isolate(Isolate* original)
|
|||
main_port_(0),
|
||||
pause_capability_(0),
|
||||
terminate_capability_(0),
|
||||
errors_fatal_(true),
|
||||
heap_(NULL),
|
||||
object_store_(NULL),
|
||||
top_exit_frame_info_(0),
|
||||
|
@ -890,7 +966,7 @@ bool Isolate::VerifyTerminateCapability(const Object& capability) const {
|
|||
|
||||
bool Isolate::AddResumeCapability(const Capability& capability) {
|
||||
// Ensure a limit for the number of resume capabilities remembered.
|
||||
static const intptr_t kMaxResumeCapabilities = kSmiMax / (6*kWordSize);
|
||||
static const intptr_t kMaxResumeCapabilities = kSmiMax / (6 * kWordSize);
|
||||
|
||||
const GrowableObjectArray& caps = GrowableObjectArray::Handle(
|
||||
this, object_store()->resume_capabilities());
|
||||
|
@ -938,6 +1014,148 @@ bool Isolate::RemoveResumeCapability(const Capability& capability) {
|
|||
}
|
||||
|
||||
|
||||
// TODO(iposva): Remove duplicated code and start using some hash based
|
||||
// structure instead of these linear lookups.
|
||||
void Isolate::AddExitListener(const SendPort& listener) {
|
||||
// Ensure a limit for the number of listeners remembered.
|
||||
static const intptr_t kMaxListeners = kSmiMax / (6 * kWordSize);
|
||||
|
||||
const GrowableObjectArray& listeners = GrowableObjectArray::Handle(
|
||||
this, object_store()->exit_listeners());
|
||||
SendPort& current = SendPort::Handle(this);
|
||||
intptr_t insertion_index = -1;
|
||||
for (intptr_t i = 0; i < listeners.Length(); i++) {
|
||||
current ^= listeners.At(i);
|
||||
if (current.IsNull()) {
|
||||
if (insertion_index < 0) {
|
||||
insertion_index = i;
|
||||
}
|
||||
} else if (current.Id() == listener.Id()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (insertion_index < 0) {
|
||||
if (listeners.Length() >= kMaxListeners) {
|
||||
// Cannot grow the array of listeners beyond its max. Additional
|
||||
// listeners are ignored. In practice will never happen as we will
|
||||
// run out of memory beforehand.
|
||||
return;
|
||||
}
|
||||
listeners.Add(listener);
|
||||
} else {
|
||||
listeners.SetAt(insertion_index, listener);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Isolate::RemoveExitListener(const SendPort& listener) {
|
||||
const GrowableObjectArray& listeners = GrowableObjectArray::Handle(
|
||||
this, object_store()->exit_listeners());
|
||||
SendPort& current = SendPort::Handle(this);
|
||||
for (intptr_t i = 0; i < listeners.Length(); i++) {
|
||||
current ^= listeners.At(i);
|
||||
if (!current.IsNull() && (current.Id() == listener.Id())) {
|
||||
// Remove the matching listener from the list.
|
||||
current = SendPort::null();
|
||||
listeners.SetAt(i, current);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Isolate::NotifyExitListeners() {
|
||||
const GrowableObjectArray& listeners = GrowableObjectArray::Handle(
|
||||
this, this->object_store()->exit_listeners());
|
||||
if (listeners.IsNull()) return;
|
||||
|
||||
SendPort& listener = SendPort::Handle(this);
|
||||
for (intptr_t i = 0; i < listeners.Length(); i++) {
|
||||
listener ^= listeners.At(i);
|
||||
if (!listener.IsNull()) {
|
||||
Dart_Port port_id = listener.Id();
|
||||
uint8_t* data = NULL;
|
||||
intptr_t len = 0;
|
||||
SerializeObject(Object::null_instance(), &data, &len, false);
|
||||
Message* msg = new Message(port_id, data, len, Message::kNormalPriority);
|
||||
PortMap::PostMessage(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Isolate::AddErrorListener(const SendPort& listener) {
|
||||
// Ensure a limit for the number of listeners remembered.
|
||||
static const intptr_t kMaxListeners = kSmiMax / (6 * kWordSize);
|
||||
|
||||
const GrowableObjectArray& listeners = GrowableObjectArray::Handle(
|
||||
this, object_store()->error_listeners());
|
||||
SendPort& current = SendPort::Handle(this);
|
||||
intptr_t insertion_index = -1;
|
||||
for (intptr_t i = 0; i < listeners.Length(); i++) {
|
||||
current ^= listeners.At(i);
|
||||
if (current.IsNull()) {
|
||||
if (insertion_index < 0) {
|
||||
insertion_index = i;
|
||||
}
|
||||
} else if (current.Id() == listener.Id()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (insertion_index < 0) {
|
||||
if (listeners.Length() >= kMaxListeners) {
|
||||
// Cannot grow the array of listeners beyond its max. Additional
|
||||
// listeners are ignored. In practice will never happen as we will
|
||||
// run out of memory beforehand.
|
||||
return;
|
||||
}
|
||||
listeners.Add(listener);
|
||||
} else {
|
||||
listeners.SetAt(insertion_index, listener);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Isolate::RemoveErrorListener(const SendPort& listener) {
|
||||
const GrowableObjectArray& listeners = GrowableObjectArray::Handle(
|
||||
this, object_store()->error_listeners());
|
||||
SendPort& current = SendPort::Handle(this);
|
||||
for (intptr_t i = 0; i < listeners.Length(); i++) {
|
||||
current ^= listeners.At(i);
|
||||
if (!current.IsNull() && (current.Id() == listener.Id())) {
|
||||
// Remove the matching listener from the list.
|
||||
current = SendPort::null();
|
||||
listeners.SetAt(i, current);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Isolate::NotifyErrorListeners(const String& msg,
|
||||
const String& stacktrace) {
|
||||
const GrowableObjectArray& listeners = GrowableObjectArray::Handle(
|
||||
this, this->object_store()->error_listeners());
|
||||
if (listeners.IsNull()) return;
|
||||
|
||||
const Array& arr = Array::Handle(this, Array::New(2));
|
||||
arr.SetAt(0, msg);
|
||||
arr.SetAt(1, stacktrace);
|
||||
SendPort& listener = SendPort::Handle(this);
|
||||
for (intptr_t i = 0; i < listeners.Length(); i++) {
|
||||
listener ^= listeners.At(i);
|
||||
if (!listener.IsNull()) {
|
||||
Dart_Port port_id = listener.Id();
|
||||
uint8_t* data = NULL;
|
||||
intptr_t len = 0;
|
||||
SerializeObject(arr, &data, &len, false);
|
||||
Message* msg = new Message(port_id, data, len, Message::kNormalPriority);
|
||||
PortMap::PostMessage(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void StoreError(Isolate* isolate, const Object& obj) {
|
||||
ASSERT(obj.IsError());
|
||||
isolate->object_store()->set_sticky_error(Error::Cast(obj));
|
||||
|
@ -1170,6 +1388,11 @@ void Isolate::Shutdown() {
|
|||
StackZone stack_zone(this);
|
||||
HandleScope handle_scope(this);
|
||||
|
||||
// Notify exit listeners that this isolate is shutting down.
|
||||
if (object_store() != NULL) {
|
||||
NotifyExitListeners();
|
||||
}
|
||||
|
||||
// Clean up debugger resources.
|
||||
debugger()->Shutdown();
|
||||
|
||||
|
|
|
@ -74,6 +74,7 @@ class RawFloat32x4;
|
|||
class RawInt32x4;
|
||||
class RawUserTag;
|
||||
class SampleBuffer;
|
||||
class SendPort;
|
||||
class Simulator;
|
||||
class StackResource;
|
||||
class StackZone;
|
||||
|
@ -410,6 +411,17 @@ class Isolate : public BaseIsolate {
|
|||
bool AddResumeCapability(const Capability& capability);
|
||||
bool RemoveResumeCapability(const Capability& capability);
|
||||
|
||||
void AddExitListener(const SendPort& listener);
|
||||
void RemoveExitListener(const SendPort& listener);
|
||||
void NotifyExitListeners();
|
||||
|
||||
void AddErrorListener(const SendPort& listener);
|
||||
void RemoveErrorListener(const SendPort& listener);
|
||||
void NotifyErrorListeners(const String& msg, const String& stacktrace);
|
||||
|
||||
bool ErrorsFatal() const { return errors_fatal_; }
|
||||
void SetErrorsFatal(bool val) { errors_fatal_ = val; }
|
||||
|
||||
Random* random() { return &random_; }
|
||||
|
||||
Simulator* simulator() const { return simulator_; }
|
||||
|
@ -674,6 +686,7 @@ class Isolate : public BaseIsolate {
|
|||
Dart_Port origin_id_; // Isolates created by spawnFunc have some origin id.
|
||||
uint64_t pause_capability_;
|
||||
uint64_t terminate_capability_;
|
||||
bool errors_fatal_;
|
||||
Heap* heap_;
|
||||
ObjectStore* object_store_;
|
||||
uword top_exit_frame_info_;
|
||||
|
|
|
@ -75,6 +75,8 @@ ObjectStore::ObjectStore()
|
|||
pending_functions_(GrowableObjectArray::null()),
|
||||
pending_deferred_loads_(GrowableObjectArray::null()),
|
||||
resume_capabilities_(GrowableObjectArray::null()),
|
||||
exit_listeners_(GrowableObjectArray::null()),
|
||||
error_listeners_(GrowableObjectArray::null()),
|
||||
sticky_error_(Error::null()),
|
||||
empty_context_(Context::null()),
|
||||
stack_overflow_(Instance::null()),
|
||||
|
@ -125,6 +127,8 @@ bool ObjectStore::PreallocateObjects() {
|
|||
this->pending_deferred_loads_ = GrowableObjectArray::New();
|
||||
|
||||
this->resume_capabilities_ = GrowableObjectArray::New();
|
||||
this->exit_listeners_ = GrowableObjectArray::New();
|
||||
this->error_listeners_ = GrowableObjectArray::New();
|
||||
|
||||
Object& result = Object::Handle();
|
||||
const Library& library = Library::Handle(Library::CoreLibrary());
|
||||
|
|
|
@ -342,6 +342,14 @@ class ObjectStore {
|
|||
return resume_capabilities_;
|
||||
}
|
||||
|
||||
RawGrowableObjectArray* exit_listeners() const {
|
||||
return exit_listeners_;
|
||||
}
|
||||
|
||||
RawGrowableObjectArray* error_listeners() const {
|
||||
return error_listeners_;
|
||||
}
|
||||
|
||||
RawError* sticky_error() const { return sticky_error_; }
|
||||
void set_sticky_error(const Error& value) {
|
||||
ASSERT(!value.IsNull());
|
||||
|
@ -488,6 +496,8 @@ class ObjectStore {
|
|||
RawGrowableObjectArray* pending_functions_;
|
||||
RawGrowableObjectArray* pending_deferred_loads_;
|
||||
RawGrowableObjectArray* resume_capabilities_;
|
||||
RawGrowableObjectArray* exit_listeners_;
|
||||
RawGrowableObjectArray* error_listeners_;
|
||||
RawError* sticky_error_;
|
||||
RawContext* empty_context_;
|
||||
RawInstance* stack_overflow_;
|
||||
|
|
|
@ -47,7 +47,6 @@ Future spawn(entry) {
|
|||
main(){
|
||||
asyncStart();
|
||||
RawReceivePort reply = new RawReceivePort(null);
|
||||
RawReceivePort reply2 = new RawReceivePort(null);
|
||||
// Create two isolates waiting for commands, with errors non-fatal.
|
||||
Future iso1 = spawn(isomain1);
|
||||
Future iso2 = spawn(isomain1);
|
||||
|
|
|
@ -92,7 +92,7 @@ main(){
|
|||
case 2:
|
||||
Expect.equals(new RangeError.value(37).toString(), "$error");
|
||||
state2++;
|
||||
reply.close();
|
||||
reply2.close();
|
||||
isolate2.removeErrorListener(errorPort2.sendPort);
|
||||
errorPort2.close();
|
||||
asyncEnd();
|
||||
|
|
|
@ -11,16 +11,9 @@ mandel_isolate_test: Skip # Uses 600 MB Ram on our 1 GB test device.
|
|||
|
||||
[ $compiler == none || $compiler == dart2dart ]
|
||||
compile_time_error_test/01: Skip # Issue 12587
|
||||
ondone_test: Fail # Not implemented yet
|
||||
ping_test: Skip # Resolve test issues
|
||||
ping_pause_test: Skip # Resolve test issues
|
||||
kill_test: Fail # Not implemented yet
|
||||
kill2_test: Fail # Not implemented yet
|
||||
kill3_test: Fail # Not implemented yet
|
||||
kill_self_test: Fail # Not implemented yet
|
||||
handle_error_test: Fail # Not implemented yet
|
||||
handle_error2_test: Fail # Not implemented yet
|
||||
handle_error3_test: Fail # Not implemented yet
|
||||
kill3_test: Pass, Fail # Bad test: expects total message order
|
||||
|
||||
message3_test/constList_identical: RuntimeError # Issue 21816
|
||||
message3_test/constMap: RuntimeError # Issue 21816
|
||||
|
|
Loading…
Reference in a new issue