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