Index: runtime/bin/directory.cc |
diff --git a/runtime/bin/directory.cc b/runtime/bin/directory.cc |
index 982a4be0147d5ffad9e0696042a6f8b741c990e5..bb3173f5b63466d6d9bd5d90906edb41802f56b4 100644 |
--- a/runtime/bin/directory.cc |
+++ b/runtime/bin/directory.cc |
@@ -7,6 +7,7 @@ |
#include "bin/directory.h" |
#include "bin/dartutils.h" |
+#include "bin/log.h" |
#include "include/dart_api.h" |
#include "platform/assert.h" |
@@ -139,6 +140,61 @@ void FUNCTION_NAME(Directory_List)(Dart_NativeArguments args) { |
} |
+static const int kAsyncDirectoryListerFieldIndex = 0; |
+ |
+ |
+void FUNCTION_NAME(Directory_GetAsyncDirectoryListerPointer)( |
+ Dart_NativeArguments args) { |
+ AsyncDirectoryListing* listing; |
+ Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); |
+ ASSERT(Dart_IsInstance(dart_this)); |
+ ThrowIfError(Dart_GetNativeInstanceField( |
+ dart_this, |
+ kAsyncDirectoryListerFieldIndex, |
+ reinterpret_cast<intptr_t*>(&listing))); |
+ if (listing != NULL) { |
+ intptr_t listing_pointer = reinterpret_cast<intptr_t>(listing); |
+ // Increment the listing's reference count. This native should only be |
+ // be called when we are about to send the AsyncDirectoryListing* to the |
+ // IO service. |
+ listing->Retain(); |
+ Dart_SetReturnValue(args, Dart_NewInteger(listing_pointer)); |
+ } |
+} |
+ |
+ |
+static void ReleaseListing(void* isolate_callback_data, |
+ Dart_WeakPersistentHandle handle, |
+ void* peer) { |
+ AsyncDirectoryListing* listing = |
+ reinterpret_cast<AsyncDirectoryListing*>(peer); |
+ listing->Release(); |
+} |
+ |
+ |
+void FUNCTION_NAME(Directory_SetAsyncDirectoryListerPointer)( |
+ Dart_NativeArguments args) { |
+ Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); |
+ intptr_t listing_pointer = |
+ DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 1)); |
+ AsyncDirectoryListing* listing = |
+ reinterpret_cast<AsyncDirectoryListing*>(listing_pointer); |
+ Dart_NewWeakPersistentHandle( |
+ dart_this, |
+ reinterpret_cast<void*>(listing), |
+ sizeof(*listing), |
+ ReleaseListing); |
+ Dart_Handle result = Dart_SetNativeInstanceField( |
+ dart_this, |
+ kAsyncDirectoryListerFieldIndex, |
+ listing_pointer); |
+ if (Dart_IsError(result)) { |
+ Log::PrintErr("SetAsyncDirectoryListerPointer failed\n"); |
+ Dart_PropagateError(result); |
+ } |
+} |
+ |
+ |
CObject* Directory::CreateRequest(const CObjectArray& request) { |
if ((request.Length() == 1) && request[0]->IsString()) { |
CObjectString path(request[0]); |
@@ -226,7 +282,7 @@ CObject* Directory::ListStartRequest(const CObjectArray& request) { |
if (dir_listing->error()) { |
// Report error now, so we capture the correct OSError. |
CObject* err = CObject::NewOSError(); |
- delete dir_listing; |
+ dir_listing->Release(); |
CObjectArray* error = new CObjectArray(CObject::NewArray(3)); |
error->SetAt(0, new CObjectInt32( |
CObject::NewInt32(AsyncDirectoryListing::kListError))); |
@@ -247,6 +303,7 @@ CObject* Directory::ListNextRequest(const CObjectArray& request) { |
CObjectIntptr ptr(request[0]); |
AsyncDirectoryListing* dir_listing = |
reinterpret_cast<AsyncDirectoryListing*>(ptr.Value()); |
+ RefCntReleaseScope<AsyncDirectoryListing> rs(dir_listing); |
if (dir_listing->IsEmpty()) { |
return new CObjectArray(CObject::NewArray(0)); |
} |
@@ -268,7 +325,15 @@ CObject* Directory::ListStopRequest(const CObjectArray& request) { |
CObjectIntptr ptr(request[0]); |
AsyncDirectoryListing* dir_listing = |
reinterpret_cast<AsyncDirectoryListing*>(ptr.Value()); |
- delete dir_listing; |
+ RefCntReleaseScope<AsyncDirectoryListing> rs(dir_listing); |
+ |
+ // We have retained a reference to the listing here. Therefore the listing's |
+ // destructor can't be running. Since no further requests are dispatched by |
+ // the Dart code after an async stop call, this PopAll() can't be racing |
+ // with any other call on the listing. We don't do an extra Release(), and |
+ // we don't delete the weak persistent handle. The file is closed here, but |
+ // the memory for the listing will be cleaned up when the finalizer runs. |
+ dir_listing->PopAll(); |
return new CObjectBool(CObject::Bool(true)); |
} |
return CreateIllegalArgumentError(); |