Index: runtime/bin/eventhandler_win.cc |
diff --git a/runtime/bin/eventhandler_win.cc b/runtime/bin/eventhandler_win.cc |
index 92c058de85b7edcdb61af56d43a0d522e13c14f2..a10dd04217902328b0fcbe77953bf7235d4115b9 100644 |
--- a/runtime/bin/eventhandler_win.cc |
+++ b/runtime/bin/eventhandler_win.cc |
@@ -24,7 +24,6 @@ static const int kInfinityTimeout = -1; |
static const int kTimeoutId = -1; |
static const int kShutdownId = -2; |
- |
IOBuffer* IOBuffer::AllocateBuffer(int buffer_size, Operation operation) { |
IOBuffer* buffer = new(buffer_size) IOBuffer(buffer_size, operation); |
return buffer; |
@@ -47,6 +46,11 @@ IOBuffer* IOBuffer::AllocateWriteBuffer(int buffer_size) { |
} |
+IOBuffer* IOBuffer::AllocateDisconnectBuffer() { |
+ return AllocateBuffer(0, kDisconnect); |
+} |
+ |
+ |
void IOBuffer::DisposeBuffer(IOBuffer* buffer) { |
delete buffer; |
} |
@@ -140,25 +144,22 @@ bool Handle::CreateCompletionPort(HANDLE completion_port) { |
} |
-void Handle::close() { |
+void Handle::Close() { |
ScopedLock lock(this); |
if (!IsClosing()) { |
// Close the socket and set the closing state. This close method can be |
// called again if this socket has pending IO operations in flight. |
ASSERT(handle_ != INVALID_HANDLE_VALUE); |
MarkClosing(); |
- // According to the documentation from Microsoft socket handles should |
- // not be closed using CloseHandle but using closesocket. |
- if (is_socket()) { |
- closesocket(reinterpret_cast<SOCKET>(handle_)); |
- } else { |
- CloseHandle(handle_); |
- } |
- handle_ = INVALID_HANDLE_VALUE; |
+ // Perform handle type specific closing. |
+ DoClose(); |
} |
+} |
+ |
- // Perform socket type specific close handling. |
- AfterClose(); |
+void Handle::DoClose() { |
+ CloseHandle(handle_); |
+ handle_ = INVALID_HANDLE_VALUE; |
} |
@@ -313,10 +314,6 @@ bool FileHandle::IsClosed() { |
} |
-void FileHandle::AfterClose() { |
-} |
- |
- |
void SocketHandle::HandleIssueError() { |
int error = WSAGetLastError(); |
if (error == WSAECONNRESET) { |
@@ -330,12 +327,6 @@ void SocketHandle::HandleIssueError() { |
bool ListenSocket::LoadAcceptEx() { |
// Load the AcceptEx function into memory using WSAIoctl. |
- // The WSAIoctl function is an extension of the ioctlsocket() |
- // function that can use overlapped I/O. The function's 3rd |
- // through 6th parameters are input and output buffers where |
- // we pass the pointer to our AcceptEx function. This is used |
- // so that we can call the AcceptEx function directly, rather |
- // than refer to the Mswsock.lib library. |
GUID guid_accept_ex = WSAID_ACCEPTEX; |
DWORD bytes; |
int status = WSAIoctl(socket(), |
@@ -403,17 +394,6 @@ void ListenSocket::AcceptComplete(IOBuffer* buffer, HANDLE completion_port) { |
SO_UPDATE_ACCEPT_CONTEXT, |
reinterpret_cast<char*>(&s), sizeof(s)); |
if (rc == NO_ERROR) { |
- linger l; |
- l.l_onoff = 1; |
- l.l_linger = 10; |
- int status = setsockopt(buffer->client(), |
- SOL_SOCKET, |
- SO_LINGER, |
- reinterpret_cast<char*>(&l), |
- sizeof(l)); |
- if (status != NO_ERROR) { |
- FATAL("Failed setting SO_LINGER on socket"); |
- } |
// Insert the accepted socket into the list. |
ClientSocket* client_socket = new ClientSocket(buffer->client(), 0); |
client_socket->CreateCompletionPort(completion_port); |
@@ -436,6 +416,27 @@ void ListenSocket::AcceptComplete(IOBuffer* buffer, HANDLE completion_port) { |
} |
+void ListenSocket::DoClose() { |
+ closesocket(socket()); |
+ handle_ = INVALID_HANDLE_VALUE; |
+ while (CanAccept()) { |
+ // Get rid of connections already accepted. |
+ ClientSocket *client = Accept(); |
+ if (client != NULL) { |
+ client->Close(); |
+ } else { |
+ break; |
+ } |
+ } |
+} |
+ |
+ |
+bool ListenSocket::CanAccept() { |
+ ScopedLock lock(this); |
+ return accepted_head_ != NULL; |
+} |
+ |
+ |
ClientSocket* ListenSocket::Accept() { |
ScopedLock lock(this); |
if (accepted_head_ == NULL) return NULL; |
@@ -460,20 +461,6 @@ void ListenSocket::EnsureInitialized( |
} |
-void ListenSocket::AfterClose() { |
- ScopedLock lock(this); |
- while (true) { |
- // Get rid of connections already accepted. |
- ClientSocket *client = Accept(); |
- if (client != NULL) { |
- client->close(); |
- } else { |
- break; |
- } |
- } |
-} |
- |
- |
bool ListenSocket::IsClosed() { |
return IsClosing() && !HasPendingAccept(); |
} |
@@ -527,11 +514,29 @@ int Handle::Write(const void* buffer, int num_bytes) { |
} |
+bool ClientSocket::LoadDisconnectEx() { |
+ // Load the DisconnectEx function into memory using WSAIoctl. |
+ GUID guid_disconnect_ex = WSAID_DISCONNECTEX; |
+ DWORD bytes; |
+ int status = WSAIoctl(socket(), |
+ SIO_GET_EXTENSION_FUNCTION_POINTER, |
+ &guid_disconnect_ex, |
+ sizeof(guid_disconnect_ex), |
+ &DisconnectEx_, |
+ sizeof(DisconnectEx_), |
+ &bytes, |
+ NULL, |
+ NULL); |
+ if (status == SOCKET_ERROR) { |
+ Log::PrintErr("Error WSAIoctl failed: %d\n", WSAGetLastError()); |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+ |
void ClientSocket::Shutdown(int how) { |
int rc = shutdown(socket(), how); |
- if (rc == SOCKET_ERROR) { |
- Log::PrintErr("shutdown failed: %d %d\n", socket(), WSAGetLastError()); |
- } |
if (how == SD_RECEIVE) MarkClosedRead(); |
if (how == SD_SEND) MarkClosedWrite(); |
if (how == SD_BOTH) { |
@@ -541,6 +546,13 @@ void ClientSocket::Shutdown(int how) { |
} |
+void ClientSocket::DoClose() { |
+ // Always do a suhtdown before initiating a disconnect. |
+ shutdown(socket(), SD_BOTH); |
+ IssueDisconnect(); |
+} |
+ |
+ |
bool ClientSocket::IssueRead() { |
ScopedLock lock(this); |
ASSERT(completion_port_ != INVALID_HANDLE_VALUE); |
@@ -591,6 +603,27 @@ bool ClientSocket::IssueWrite() { |
} |
+void ClientSocket::IssueDisconnect() { |
+ IOBuffer* buffer = IOBuffer::AllocateDisconnectBuffer(); |
+ BOOL ok = DisconnectEx_( |
+ socket(), buffer->GetCleanOverlapped(), TF_REUSE_SOCKET, 0); |
+ if (!ok && WSAGetLastError() != WSA_IO_PENDING) { |
+ DisconnectComplete(buffer); |
+ } |
+} |
+ |
+ |
+void ClientSocket::DisconnectComplete(IOBuffer* buffer) { |
+ IOBuffer::DisposeBuffer(buffer); |
+ closesocket(socket()); |
+ if (data_ready_ != NULL) { |
+ IOBuffer::DisposeBuffer(data_ready_); |
+ } |
+ // When disconnect is complete get rid of the object. |
+ delete this; |
+} |
+ |
+ |
void ClientSocket::EnsureInitialized( |
EventHandlerImplementation* event_handler) { |
ScopedLock lock(this); |
@@ -602,17 +635,8 @@ void ClientSocket::EnsureInitialized( |
} |
-void ClientSocket::AfterClose() { |
- ScopedLock lock(this); |
- if (data_ready_ != NULL) { |
- IOBuffer::DisposeBuffer(data_ready_); |
- data_ready_ = NULL; |
- } |
-} |
- |
- |
bool ClientSocket::IsClosed() { |
- return IsClosing() && !HasPendingRead() && !HasPendingWrite(); |
+ return false; |
} |
@@ -636,49 +660,61 @@ void EventHandlerImplementation::HandleInterrupt(InterruptMessage* msg) { |
Handle::ScopedLock lock(listen_socket); |
- // If incomming connections are requested make sure that pending accepts |
- // are issued. |
+ // If incomming connections are requested make sure to post already |
+ // accepted connections. |
if ((msg->data & (1 << kInEvent)) != 0) { |
+ if (listen_socket->CanAccept()) { |
+ int event_mask = (1 << kInEvent); |
+ handle->set_mask(handle->mask() & ~event_mask); |
+ DartUtils::PostInt32(handle->port(), event_mask); |
+ } |
+ // Always keep 5 outstanding accepts going, to enhance performance. |
while (listen_socket->pending_accept_count() < 5) { |
listen_socket->IssueAccept(); |
} |
} |
if ((msg->data & (1 << kCloseCommand)) != 0) { |
- listen_socket->close(); |
+ listen_socket->Close(); |
if (listen_socket->IsClosed()) { |
delete_handle = true; |
} |
} |
} else { |
- handle->SetPortAndMask(msg->dart_port, msg->data); |
handle->EnsureInitialized(this); |
Handle::ScopedLock lock(handle); |
if (!handle->IsError()) { |
- // If in events (data available events) have been requested, and data |
- // is available, post an in event immediately. Otherwise make sure |
- // that a pending read is issued, unless the socket is already closed |
- // for read. |
- if ((msg->data & (1 << kInEvent)) != 0) { |
- if (handle->Available() > 0) { |
- int event_mask = (1 << kInEvent); |
- handle->set_mask(handle->mask() & ~event_mask); |
- DartUtils::PostInt32(handle->port(), event_mask); |
- } else if (!handle->HasPendingRead() && |
- !handle->IsClosedRead()) { |
- handle->IssueRead(); |
+ if ((msg->data & ((1 << kInEvent) | (1 << kOutEvent))) != 0) { |
+ // Only set mask if we turned on kInEvent or kOutEvent. |
+ handle->SetPortAndMask(msg->dart_port, msg->data); |
+ |
+ // If in events (data available events) have been requested, and data |
+ // is available, post an in event immediately. Otherwise make sure |
+ // that a pending read is issued, unless the socket is already closed |
+ // for read. |
+ if ((msg->data & (1 << kInEvent)) != 0) { |
+ if (handle->Available() > 0) { |
+ int event_mask = (1 << kInEvent); |
+ handle->set_mask(handle->mask() & ~event_mask); |
+ DartUtils::PostInt32(handle->port(), event_mask); |
+ } else if (handle->IsClosedRead()) { |
+ int event_mask = (1 << kCloseEvent); |
+ DartUtils::PostInt32(handle->port(), event_mask); |
+ } else if (!handle->HasPendingRead()) { |
+ handle->IssueRead(); |
+ } |
} |
- } |
- // If out events (can write events) have been requested, and there |
- // are no pending writes, post an out event immediately. |
- if ((msg->data & (1 << kOutEvent)) != 0) { |
- if (!handle->HasPendingWrite()) { |
- int event_mask = (1 << kOutEvent); |
- handle->set_mask(handle->mask() & ~event_mask); |
- DartUtils::PostInt32(handle->port(), event_mask); |
+ // If out events (can write events) have been requested, and there |
+ // are no pending writes, post an out event immediately. |
+ if ((msg->data & (1 << kOutEvent)) != 0) { |
+ if (!handle->HasPendingWrite()) { |
+ int event_mask = (1 << kOutEvent); |
+ handle->set_mask(handle->mask() & ~event_mask); |
+ DartUtils::PostInt32(handle->port(), event_mask); |
+ } |
} |
} |
@@ -695,7 +731,7 @@ void EventHandlerImplementation::HandleInterrupt(InterruptMessage* msg) { |
} |
if ((msg->data & (1 << kCloseCommand)) != 0) { |
- handle->close(); |
+ handle->Close(); |
if (handle->IsClosed()) { |
delete_handle = true; |
} |
@@ -794,6 +830,13 @@ void EventHandlerImplementation::HandleWrite(Handle* handle, |
} |
+void EventHandlerImplementation::HandleDisconnect( |
+ ClientSocket* client_socket, |
+ int bytes, |
+ IOBuffer* buffer) { |
+ client_socket->DisconnectComplete(buffer); |
+} |
+ |
void EventHandlerImplementation::HandleTimeout() { |
// TODO(sgjesse) check if there actually is a timeout. |
DartUtils::PostNull(timeout_port_); |
@@ -822,6 +865,11 @@ void EventHandlerImplementation::HandleIOCompletion(DWORD bytes, |
HandleWrite(handle, bytes, buffer); |
break; |
} |
+ case IOBuffer::kDisconnect: { |
+ ClientSocket* client_socket = reinterpret_cast<ClientSocket*>(key); |
+ HandleDisconnect(client_socket, bytes, buffer); |
+ break; |
+ } |
default: |
UNREACHABLE(); |
} |