From 354bb40e75d94466e91fe6960523612c9d17ccfb Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Thu, 2 Nov 2017 23:11:29 +0300 Subject: Add implementation --- mysql/vio/vioshm.c | 226 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 226 insertions(+) create mode 100644 mysql/vio/vioshm.c (limited to 'mysql/vio/vioshm.c') 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) */ + -- cgit v1.1