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
37static 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/**@{*/
53extern "C"
54{
55static void scheduler_wait_lock_begin(void) {
56 thd_wait_begin(NULL, THD_WAIT_TABLE_LOCK);
57}
58
59static void scheduler_wait_lock_end(void) {
60 thd_wait_end(NULL);
61}
62
63static void scheduler_wait_sync_begin(void) {
64 thd_wait_begin(NULL, THD_WAIT_SYNC);
65}
66
67static void scheduler_wait_sync_end(void) {
68 thd_wait_end(NULL);
69}
70
71static void scheduler_wait_net_begin(void) {
72 thd_wait_begin(NULL, THD_WAIT_NET);
73}
74
75static 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
90void 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
111void 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
128void 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
142bool init_new_connection_handler_thread()
143{
144 return 0;
145}
146void handle_connection_in_main_thread(CONNECT *connect)
147{
148}
149#endif
150
151/*
152 Initialize scheduler for --thread-handling=no-threads
153*/
154
155void 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