MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
vioshm.c
1 /* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 #include "vio_priv.h"
17 
18 #if defined(_WIN32) && defined(HAVE_SMEM)
19 
20 size_t vio_read_shared_memory(Vio *vio, uchar *buf, size_t size)
21 {
22  size_t length;
23  size_t remain_local;
24  char *current_position;
25  HANDLE events[2];
26  DWORD timeout;
27  DBUG_ENTER("vio_read_shared_memory");
28 
29  remain_local= size;
30  current_position= buf;
31  timeout= vio->read_timeout >= 0 ? vio->read_timeout : INFINITE;
32 
33  events[0]= vio->event_server_wrote;
34  events[1]= vio->event_conn_closed;
35 
36  do
37  {
38  if (vio->shared_memory_remain == 0)
39  {
40  DWORD wait_status;
41 
42  wait_status= WaitForMultipleObjects(array_elements(events), events,
43  FALSE, timeout);
44 
45  /*
46  WaitForMultipleObjects can return next values:
47  WAIT_OBJECT_0+0 - event from vio->event_server_wrote
48  WAIT_OBJECT_0+1 - event from vio->event_conn_closed.
49  We can't read anything
50  WAIT_ABANDONED_0 and WAIT_TIMEOUT - fail. We can't read anything
51  */
52  if (wait_status != WAIT_OBJECT_0)
53  {
54  /*
55  If wait_status is WAIT_TIMEOUT, set error code to indicate a
56  timeout error. If vio->event_conn_closed was set, use an EOF
57  condition (return value of zero) to indicate that the operation
58  has been aborted.
59  */
60  if (wait_status == WAIT_TIMEOUT)
61  SetLastError(SOCKET_ETIMEDOUT);
62  else if (wait_status == (WAIT_OBJECT_0 + 1))
63  DBUG_RETURN(0);
64 
65  DBUG_RETURN(-1);
66  }
67 
68  vio->shared_memory_pos= vio->handle_map;
69  vio->shared_memory_remain= uint4korr((ulong*)vio->shared_memory_pos);
70  vio->shared_memory_pos+= 4;
71  }
72 
73  length= size;
74 
75  if (vio->shared_memory_remain < length)
76  length= vio->shared_memory_remain;
77  if (length > remain_local)
78  length= remain_local;
79 
80  memcpy(current_position, vio->shared_memory_pos, length);
81 
82  vio->shared_memory_remain-= length;
83  vio->shared_memory_pos+= length;
84  current_position+= length;
85  remain_local-= length;
86 
87  if (!vio->shared_memory_remain)
88  {
89  if (!SetEvent(vio->event_client_read))
90  DBUG_RETURN(-1);
91  }
92  } while (remain_local);
93  length= size;
94 
95  DBUG_RETURN(length);
96 }
97 
98 
99 size_t vio_write_shared_memory(Vio *vio, const uchar *buf, size_t size)
100 {
101  size_t length, remain, sz;
102  HANDLE pos;
103  const uchar *current_position;
104  HANDLE events[2];
105  DWORD timeout;
106  DBUG_ENTER("vio_write_shared_memory");
107 
108  remain= size;
109  current_position= buf;
110  timeout= vio->write_timeout >= 0 ? vio->write_timeout : INFINITE;
111 
112  events[0]= vio->event_server_read;
113  events[1]= vio->event_conn_closed;
114 
115  while (remain != 0)
116  {
117  DWORD wait_status;
118 
119  wait_status= WaitForMultipleObjects(array_elements(events), events,
120  FALSE, timeout);
121 
122  if (wait_status != WAIT_OBJECT_0)
123  {
124  /* Set error code to indicate a timeout error or disconnect. */
125  if (wait_status == WAIT_TIMEOUT)
126  SetLastError(SOCKET_ETIMEDOUT);
127  else
128  SetLastError(ERROR_GRACEFUL_DISCONNECT);
129 
130  DBUG_RETURN((size_t) -1);
131  }
132 
133  sz= (remain > shared_memory_buffer_length ? shared_memory_buffer_length :
134  remain);
135 
136  int4store(vio->handle_map, sz);
137  pos= vio->handle_map + 4;
138  memcpy(pos, current_position, sz);
139  remain-= sz;
140  current_position+= sz;
141  if (!SetEvent(vio->event_client_wrote))
142  DBUG_RETURN((size_t) -1);
143  }
144  length= size;
145 
146  DBUG_RETURN(length);
147 }
148 
149 
150 my_bool vio_is_connected_shared_memory(Vio *vio)
151 {
152  return (WaitForSingleObject(vio->event_conn_closed, 0) != WAIT_OBJECT_0);
153 }
154 
155 
156 void vio_delete_shared_memory(Vio *vio)
157 {
158  DBUG_ENTER("vio_delete_shared_memory");
159 
160  if (!vio)
161  DBUG_VOID_RETURN;
162 
163  if (vio->inactive == FALSE)
164  vio->vioshutdown(vio);
165 
166  /*
167  Close all handlers. UnmapViewOfFile and CloseHandle return non-zero
168  result if they are success.
169  */
170  if (UnmapViewOfFile(vio->handle_map) == 0)
171  DBUG_PRINT("vio_error", ("UnmapViewOfFile() failed"));
172 
173  if (CloseHandle(vio->event_server_wrote) == 0)
174  DBUG_PRINT("vio_error", ("CloseHandle(vio->esw) failed"));
175 
176  if (CloseHandle(vio->event_server_read) == 0)
177  DBUG_PRINT("vio_error", ("CloseHandle(vio->esr) failed"));
178 
179  if (CloseHandle(vio->event_client_wrote) == 0)
180  DBUG_PRINT("vio_error", ("CloseHandle(vio->ecw) failed"));
181 
182  if (CloseHandle(vio->event_client_read) == 0)
183  DBUG_PRINT("vio_error", ("CloseHandle(vio->ecr) failed"));
184 
185  if (CloseHandle(vio->handle_file_map) == 0)
186  DBUG_PRINT("vio_error", ("CloseHandle(vio->hfm) failed"));
187 
188  if (CloseHandle(vio->event_conn_closed) == 0)
189  DBUG_PRINT("vio_error", ("CloseHandle(vio->ecc) failed"));
190 
191  vio_delete(vio);
192 
193  DBUG_VOID_RETURN;
194 }
195 
196 /*
197  When "kill connection xx" is executed on an arbitrary thread it calls
198  THD::shutdown_active_vio() on the THD referred to by xx. Since the
199  thread serving the connection xx might be in the middle of a vio_read
200  or vio_write, we cannot unmap the shared memory here.
201 
202  Therefore we here just signal the connection_closed event and give
203  the thread servicing connection xx a chance to gracefully exit.
204  All handles are closed and the VIO is cleaned up when vio_delete() is
205  called and this completes the vio cleanup operation in its entirety.
206 */
207 int vio_shutdown_shared_memory(Vio * vio)
208 {
209  DBUG_ENTER("vio_shutdown_shared_memory");
210  if (vio->inactive == FALSE)
211  {
212  /*
213  Set event_conn_closed for notification of both client and server that
214  connection is closed
215  */
216  SetEvent(vio->event_conn_closed);
217  }
218 
219  vio->inactive= TRUE;
220  vio->mysql_socket= MYSQL_INVALID_SOCKET;
221 
222  DBUG_RETURN(0);
223 }
224 
225 #endif /* #if defined(_WIN32) && defined(HAVE_SMEM) */
226