1 /* Copyright (c) 2007, 2013, Oracle and/or its affiliates.
2    Copyright (c) 2012, 2014, SkySQL Ab.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; version 2 of the License.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 
13    You should have received a copy of the GNU General Public License
14    along with this program; if not, write to the Free Software
15    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335  USA */
16 
17 /*
18   Implementation for the thread scheduler
19 */
20 
21 #ifdef USE_PRAGMA_INTERFACE
22 #pragma implementation
23 #endif
24 
25 #include "mariadb.h"
26 #include "mysqld.h"
27 #include "sql_connect.h"         // init_new_connection_handler_thread
28 #include "scheduler.h"
29 #include "sql_class.h"
30 #include "sql_callback.h"
31 #include <violite.h>
32 
33 /*
34   End connection, in case when we are using 'no-threads'
35 */
36 
no_threads_end(THD * thd,bool put_in_cache)37 static bool no_threads_end(THD *thd, bool put_in_cache)
38 {
39   if (thd)
40   {
41     unlink_thd(thd);
42     delete thd;
43   }
44   return 1;                                     // Abort handle_one_connection
45 }
46 
47 /** @internal
48   Helper functions to allow mysys to call the thread scheduler when
49   waiting for locks.
50 */
51 
52 /**@{*/
53 extern "C"
54 {
scheduler_wait_lock_begin(void)55 static void scheduler_wait_lock_begin(void) {
56   thd_wait_begin(NULL, THD_WAIT_TABLE_LOCK);
57 }
58 
scheduler_wait_lock_end(void)59 static void scheduler_wait_lock_end(void) {
60   thd_wait_end(NULL);
61 }
62 
scheduler_wait_sync_begin(void)63 static void scheduler_wait_sync_begin(void) {
64   thd_wait_begin(NULL, THD_WAIT_SYNC);
65 }
66 
scheduler_wait_sync_end(void)67 static void scheduler_wait_sync_end(void) {
68   thd_wait_end(NULL);
69 }
70 
scheduler_wait_net_begin(void)71 static void scheduler_wait_net_begin(void) {
72    thd_wait_begin(NULL, THD_WAIT_NET);
73 }
74 
scheduler_wait_net_end(void)75 static void scheduler_wait_net_end(void) {
76    thd_wait_end(NULL);
77 }
78 
79 };
80 /**@}*/
81 
82 /**
83   Common scheduler init function.
84 
85   The scheduler is either initialized by calling
86   one_thread_scheduler() or one_thread_per_connection_scheduler() in
87   mysqld.cc, so this init function will always be called.
88  */
89 
scheduler_init()90 void scheduler_init()
91 {
92   thr_set_lock_wait_callback(scheduler_wait_lock_begin,
93                              scheduler_wait_lock_end);
94   thr_set_sync_wait_callback(scheduler_wait_sync_begin,
95                              scheduler_wait_sync_end);
96 
97   vio_set_wait_callback(scheduler_wait_net_begin,
98     scheduler_wait_net_end);
99 }
100 
101 
102 /**
103   Kill notification callback,  used by  one-thread-per-connection
104   and threadpool scheduler.
105 
106   Wakes up a thread that is stuck in read/poll/epoll/event-poll
107   routines used by threadpool, such that subsequent attempt to
108   read from  client connection will result in IO error.
109 */
110 
post_kill_notification(THD * thd)111 void post_kill_notification(THD *thd)
112 {
113   DBUG_ENTER("post_kill_notification");
114   if (current_thd == thd || thd->system_thread)
115     DBUG_VOID_RETURN;
116 
117   if (thd->net.vio)
118     vio_shutdown(thd->net.vio, SHUT_RD);
119   DBUG_VOID_RETURN;
120 }
121 
122 /*
123   Initialize scheduler for --thread-handling=one-thread-per-connection
124 */
125 
126 #ifndef EMBEDDED_LIBRARY
127 
one_thread_per_connection_scheduler(scheduler_functions * func,ulong * arg_max_connections,uint * arg_connection_count)128 void one_thread_per_connection_scheduler(scheduler_functions *func,
129     ulong *arg_max_connections,
130     uint *arg_connection_count)
131 {
132   scheduler_init();
133   func->max_threads= *arg_max_connections + 1;
134   func->max_connections= arg_max_connections;
135   func->connection_count= arg_connection_count;
136   func->init_new_connection_thread= init_new_connection_handler_thread;
137   func->add_connection= create_thread_to_handle_connection;
138   func->end_thread= one_thread_per_connection_end;
139   func->post_kill_notification= post_kill_notification;
140 }
141 #else
init_new_connection_handler_thread()142 bool init_new_connection_handler_thread()
143 {
144   return 0;
145 }
handle_connection_in_main_thread(CONNECT * connect)146 void handle_connection_in_main_thread(CONNECT *connect)
147 {
148 }
149 #endif
150 
151 /*
152   Initialize scheduler for --thread-handling=no-threads
153 */
154 
one_thread_scheduler(scheduler_functions * func)155 void one_thread_scheduler(scheduler_functions *func)
156 {
157   scheduler_init();
158   func->max_threads= 1;
159   func->max_connections= &max_connections;
160   func->connection_count= &connection_count;
161   func->init_new_connection_thread= init_new_connection_handler_thread;
162   func->add_connection= handle_connection_in_main_thread;
163   func->end_thread= no_threads_end;
164 }
165