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-1301 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 | |
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 | { |
55 | static void scheduler_wait_lock_begin(void) { |
56 | thd_wait_begin(NULL, THD_WAIT_TABLE_LOCK); |
57 | } |
58 | |
59 | static void scheduler_wait_lock_end(void) { |
60 | thd_wait_end(NULL); |
61 | } |
62 | |
63 | static void scheduler_wait_sync_begin(void) { |
64 | thd_wait_begin(NULL, THD_WAIT_SYNC); |
65 | } |
66 | |
67 | static void scheduler_wait_sync_end(void) { |
68 | thd_wait_end(NULL); |
69 | } |
70 | |
71 | static void scheduler_wait_net_begin(void) { |
72 | thd_wait_begin(NULL, THD_WAIT_NET); |
73 | } |
74 | |
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 | |
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 | |
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 | |
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 |
142 | bool init_new_connection_handler_thread() |
143 | { |
144 | return 0; |
145 | } |
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 | |
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 | |