Drizzled Public API Documentation

multi_thread.cc
1 /* Copyright (C) 2006 MySQL AB
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 <config.h>
17 
18 #include <iostream>
19 
20 #include <drizzled/pthread_globals.h>
22 #include <drizzled/errmsg_print.h>
23 #include <drizzled/session.h>
24 #include <drizzled/session/cache.h>
25 #include <drizzled/abort_exception.h>
26 #include <drizzled/transaction_services.h>
27 #include <drizzled/gettext.h>
28 #include <drizzled/plugin.h>
29 #include <drizzled/statistics_variables.h>
30 
31 #include <boost/thread.hpp>
32 #include <boost/bind.hpp>
33 #include <boost/program_options.hpp>
34 
35 #include "multi_thread.h"
36 
37 namespace po= boost::program_options;
38 using namespace std;
39 using namespace drizzled;
40 
41 /* Configuration variables. */
43 static max_threads_constraint max_threads;
44 
45 namespace drizzled
46 {
47  extern size_t my_thread_stack_size;
48 }
49 
50 namespace multi_thread {
51 
52 void MultiThreadScheduler::runSession(drizzled::session_id_t id)
53 {
54  char stack_dummy;
55  boost::this_thread::disable_interruption disable_by_default;
56 
57  Session::shared_ptr session(session::Cache::find(id));
58 
59  try
60  {
61 
62  if (not session)
63  {
64  std::cerr << _("Session killed before thread could execute") << endl;
65  return;
66  }
67  session->pushInterrupt(&disable_by_default);
68  drizzled::internal::my_thread_init();
69  session->thread_stack= (char*) &stack_dummy;
70  session->run();
71 
72  killSessionNow(session);
73  }
74  catch (abort_exception& ex)
75  {
76  cout << _("Drizzle has receieved an abort event.") << endl;
77  cout << _("In Function: ") << *::boost::get_error_info<boost::throw_function>(ex) << endl;
78  cout << _("In File: ") << *::boost::get_error_info<boost::throw_file>(ex) << endl;
79  cout << _("On Line: ") << *::boost::get_error_info<boost::throw_line>(ex) << endl;
80 
81  TransactionServices::sendShutdownEvent(*session.get());
82  }
83  // @todo remove hard spin by disconnection the session first from the
84  // thread.
85  while (not session.unique()) {}
86 }
87 
88 void MultiThreadScheduler::setStackSize()
89 {
90  pthread_attr_t attr;
91 
92  (void) pthread_attr_init(&attr);
93 
94  /* Get the thread stack size that the OS will use and make sure
95  that we update our global variable. */
96  int err= pthread_attr_getstacksize(&attr, &my_thread_stack_size);
97  pthread_attr_destroy(&attr);
98 
99  if (err != 0)
100  {
101  errmsg_printf(error::ERROR, _("Unable to get thread stack size"));
102  my_thread_stack_size= 524288; // At the time of the writing of this code, this was OSX's
103  }
104 
105  if (my_thread_stack_size == 0)
106  {
107  my_thread_stack_size= 524288; // At the time of the writing of this code, this was OSX's
108  }
109 #ifdef __sun
110  /*
111  * Solaris will return zero for the stack size in a call to
112  * pthread_attr_getstacksize() to indicate that the OS default stack
113  * size is used. We need an actual value in my_thread_stack_size so that
114  * check_stack_overrun() will work. The Solaris man page for the
115  * pthread_attr_getstacksize() function says that 2M is used for 64-bit
116  * processes. We'll explicitly set it here to make sure that is what
117  * will be used.
118  */
119  if (my_thread_stack_size == 0)
120  {
121  my_thread_stack_size= 2 * 1024 * 1024;
122  }
123 #endif
124 }
125 
126 bool MultiThreadScheduler::addSession(const Session::shared_ptr& session)
127 {
128  if (thread_count >= max_threads)
129  return true;
130 
131  thread_count.increment();
132  try
133  {
134  session->getThread().reset(new boost::thread((boost::bind(&MultiThreadScheduler::runSession, this, session->getSessionId()))));
135  }
136  catch (std::exception&)
137  {
138  thread_count.decrement();
139  return true;
140  }
141 
142  if (not session->getThread())
143  {
144  thread_count.decrement();
145  return true;
146  }
147 
148  if (not session->getThread()->joinable())
149  {
150  thread_count.decrement();
151  return true;
152  }
153 
154  return false;
155 }
156 
157 
158 void MultiThreadScheduler::killSession(Session *session)
159 {
160  thread_ptr thread(session->getThread());
161 
162  if (thread)
163  {
164  thread->interrupt();
165  }
166 }
167 
168 void MultiThreadScheduler::killSessionNow(const Session::shared_ptr& session)
169 {
170  killSession(session.get());
171 
172  session->disconnect();
173 
174  /* Locks LOCK_thread_count and deletes session */
175  Session::unlink(session);
176  thread_count.decrement();
177 }
178 
179 MultiThreadScheduler::~MultiThreadScheduler()
180 {
181  boost::mutex::scoped_lock scopedLock(drizzled::session::Cache::mutex());
182  while (thread_count)
183  {
184  COND_thread_count.wait(scopedLock);
185  }
186 }
187 
188 } // multi_thread namespace
189 
190 
191 static int init(drizzled::module::Context &context)
192 {
193 
194  context.add(new multi_thread::MultiThreadScheduler("multi_thread"));
195 
196  return 0;
197 }
198 
199 static void init_options(drizzled::module::option_context &context)
200 {
201  context("max-threads",
202  po::value<max_threads_constraint>(&max_threads)->default_value(2048),
203  _("Maximum number of user threads available."));
204 }
205 
206 DRIZZLE_DECLARE_PLUGIN
207 {
208  DRIZZLE_VERSION_ID,
209  "multi_thread",
210  "0.1",
211  "Brian Aker",
212  N_("Multi-thread scheduler"),
213  PLUGIN_LICENSE_GPL,
214  init,
215  NULL,
216  init_options
217 }
218 DRIZZLE_DECLARE_PLUGIN_END;
TODO: Rename this file - func.h is stupid.
An Proxy Wrapper around boost::program_options::variables_map.