aboutsummaryrefslogtreecommitdiff
path: root/mysql/vio/vioshm.c
diff options
context:
space:
mode:
Diffstat (limited to 'mysql/vio/vioshm.c')
-rw-r--r--mysql/vio/vioshm.c226
1 files changed, 226 insertions, 0 deletions
diff --git a/mysql/vio/vioshm.c b/mysql/vio/vioshm.c
new file mode 100644
index 0000000..9bc3976
--- /dev/null
+++ b/mysql/vio/vioshm.c
@@ -0,0 +1,226 @@
+/* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+#include "vio_priv.h"
+
+#if !defined(EMBEDDED_LIBRARY)
+
+size_t vio_read_shared_memory(Vio *vio, uchar *buf, size_t size)
+{
+ size_t length;
+ size_t remain_local;
+ char *current_position;
+ HANDLE events[2];
+ DWORD timeout;
+ DBUG_ENTER("vio_read_shared_memory");
+
+ remain_local= size;
+ current_position= buf;
+ timeout= vio->read_timeout >= 0 ? vio->read_timeout : INFINITE;
+
+ events[0]= vio->event_server_wrote;
+ events[1]= vio->event_conn_closed;
+
+ do
+ {
+ if (vio->shared_memory_remain == 0)
+ {
+ DWORD wait_status;
+
+ wait_status= WaitForMultipleObjects(array_elements(events), events,
+ FALSE, timeout);
+
+ /*
+ WaitForMultipleObjects can return next values:
+ WAIT_OBJECT_0+0 - event from vio->event_server_wrote
+ WAIT_OBJECT_0+1 - event from vio->event_conn_closed.
+ We can't read anything
+ WAIT_ABANDONED_0 and WAIT_TIMEOUT - fail. We can't read anything
+ */
+ if (wait_status != WAIT_OBJECT_0)
+ {
+ /*
+ If wait_status is WAIT_TIMEOUT, set error code to indicate a
+ timeout error. If vio->event_conn_closed was set, use an EOF
+ condition (return value of zero) to indicate that the operation
+ has been aborted.
+ */
+ if (wait_status == WAIT_TIMEOUT)
+ SetLastError(SOCKET_ETIMEDOUT);
+ else if (wait_status == (WAIT_OBJECT_0 + 1))
+ DBUG_RETURN(0);
+
+ DBUG_RETURN(-1);
+ }
+
+ vio->shared_memory_pos= vio->handle_map;
+ vio->shared_memory_remain= uint4korr(vio->shared_memory_pos);
+ vio->shared_memory_pos+= 4;
+ }
+
+ length= size;
+
+ if (vio->shared_memory_remain < length)
+ length= vio->shared_memory_remain;
+ if (length > remain_local)
+ length= remain_local;
+
+ memcpy(current_position, vio->shared_memory_pos, length);
+
+ vio->shared_memory_remain-= length;
+ vio->shared_memory_pos+= length;
+ current_position+= length;
+ remain_local-= length;
+
+ if (!vio->shared_memory_remain)
+ {
+ if (!SetEvent(vio->event_client_read))
+ DBUG_RETURN(-1);
+ }
+ } while (remain_local);
+ length= size;
+
+ DBUG_RETURN(length);
+}
+
+
+size_t vio_write_shared_memory(Vio *vio, const uchar *buf, size_t size)
+{
+ size_t length, remain, sz;
+ HANDLE pos;
+ const uchar *current_position;
+ HANDLE events[2];
+ DWORD timeout;
+ DBUG_ENTER("vio_write_shared_memory");
+
+ remain= size;
+ current_position= buf;
+ timeout= vio->write_timeout >= 0 ? vio->write_timeout : INFINITE;
+
+ events[0]= vio->event_server_read;
+ events[1]= vio->event_conn_closed;
+
+ while (remain != 0)
+ {
+ DWORD wait_status;
+
+ wait_status= WaitForMultipleObjects(array_elements(events), events,
+ FALSE, timeout);
+
+ if (wait_status != WAIT_OBJECT_0)
+ {
+ /* Set error code to indicate a timeout error or disconnect. */
+ if (wait_status == WAIT_TIMEOUT)
+ SetLastError(SOCKET_ETIMEDOUT);
+ else
+ SetLastError(ERROR_GRACEFUL_DISCONNECT);
+
+ DBUG_RETURN((size_t) -1);
+ }
+
+ sz= (remain > shared_memory_buffer_length ? shared_memory_buffer_length :
+ remain);
+
+ int4store(vio->handle_map, (uint32)sz);
+ pos= vio->handle_map + 4;
+ memcpy(pos, current_position, sz);
+ remain-= sz;
+ current_position+= sz;
+ if (!SetEvent(vio->event_client_wrote))
+ DBUG_RETURN((size_t) -1);
+ }
+ length= size;
+
+ DBUG_RETURN(length);
+}
+
+
+my_bool vio_is_connected_shared_memory(Vio *vio)
+{
+ return (WaitForSingleObject(vio->event_conn_closed, 0) != WAIT_OBJECT_0);
+}
+
+
+void vio_delete_shared_memory(Vio *vio)
+{
+ DBUG_ENTER("vio_delete_shared_memory");
+
+ if (!vio)
+ DBUG_VOID_RETURN;
+
+ if (vio->inactive == FALSE)
+ vio->vioshutdown(vio);
+
+ /*
+ Close all handlers. UnmapViewOfFile and CloseHandle return non-zero
+ result if they are success.
+ */
+ if (UnmapViewOfFile(vio->handle_map) == 0)
+ DBUG_PRINT("vio_error", ("UnmapViewOfFile() failed"));
+
+ if (CloseHandle(vio->event_server_wrote) == 0)
+ DBUG_PRINT("vio_error", ("CloseHandle(vio->esw) failed"));
+
+ if (CloseHandle(vio->event_server_read) == 0)
+ DBUG_PRINT("vio_error", ("CloseHandle(vio->esr) failed"));
+
+ if (CloseHandle(vio->event_client_wrote) == 0)
+ DBUG_PRINT("vio_error", ("CloseHandle(vio->ecw) failed"));
+
+ if (CloseHandle(vio->event_client_read) == 0)
+ DBUG_PRINT("vio_error", ("CloseHandle(vio->ecr) failed"));
+
+ if (CloseHandle(vio->handle_file_map) == 0)
+ DBUG_PRINT("vio_error", ("CloseHandle(vio->hfm) failed"));
+
+ if (CloseHandle(vio->event_conn_closed) == 0)
+ DBUG_PRINT("vio_error", ("CloseHandle(vio->ecc) failed"));
+
+ vio_delete(vio);
+
+ DBUG_VOID_RETURN;
+}
+
+/*
+ When "kill connection xx" is executed on an arbitrary thread it calls
+ THD::shutdown_active_vio() on the THD referred to by xx. Since the
+ thread serving the connection xx might be in the middle of a vio_read
+ or vio_write, we cannot unmap the shared memory here.
+
+ Therefore we here just signal the connection_closed event and give
+ the thread servicing connection xx a chance to gracefully exit.
+ All handles are closed and the VIO is cleaned up when vio_delete() is
+ called and this completes the vio cleanup operation in its entirety.
+*/
+int vio_shutdown_shared_memory(Vio * vio)
+{
+ DBUG_ENTER("vio_shutdown_shared_memory");
+ if (vio->inactive == FALSE)
+ {
+ /*
+ Set event_conn_closed for notification of both client and server that
+ connection is closed
+ */
+ SetEvent(vio->event_conn_closed);
+ }
+
+ vio->inactive= TRUE;
+ vio->mysql_socket= MYSQL_INVALID_SOCKET;
+
+ DBUG_RETURN(0);
+}
+
+#endif /* #if !defined(!EMBEDDED_LIBRARY) */
+