1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
|
/*
* Copyright (c) 2002-2014 Balabit
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As an additional exemption you are allowed to compile & link against the
* OpenSSL libraries as published by the OpenSSL project. See the file
* COPYING for details.
*
*/
#include "control-server.h"
#include "control-connection.h"
#include "control-command-thread.h"
#include "messages.h"
void
_cancel_worker(gpointer data, gpointer user_data)
{
ControlCommandThread *thread = (ControlCommandThread *) data;
msg_warning("Requesting the cancellation of control command thread",
evt_tag_str("control_command", control_command_thread_get_command(thread)));
control_command_thread_cancel(thread);
/* NOTE: threads would call control_server_worker_finished() when done (at
* least if the main loop is still executing once to process our
* thread_finished event).
*
* If finished() is called, our ref stored on the worker_threads list is
* dropped at that point.
*
* If finished() is not called (e.g. the workers are stuck and have not
* exited until our mainloop exit strategy is executed), their reference
* remains lingering on the worker_threads list.
*
* We try to take care of such lingering refs in control_server_stop(),
* which is executed already after iv_main() returns.
*/
}
void
control_server_cancel_workers(ControlServer *self)
{
if (self->worker_threads)
{
msg_debug("Cancelling control server worker threads");
g_list_foreach(self->worker_threads, _cancel_worker, NULL);
msg_debug("Control server worker threads have been cancelled");
}
}
void
control_server_worker_started(ControlServer *self, ControlCommandThread *worker)
{
control_command_thread_ref(worker);
self->worker_threads = g_list_append(self->worker_threads, worker);
}
void
control_server_worker_finished(ControlServer *self, ControlCommandThread *worker)
{
self->worker_threads = g_list_remove(self->worker_threads, worker);
control_command_thread_unref(worker);
}
void
control_server_connection_closed(ControlServer *self, ControlConnection *cc)
{
control_connection_stop_watches(cc);
control_connection_unref(cc);
}
gboolean
control_server_start_method(ControlServer *self)
{
/* NOTE: this is a placeholder and is empty for now. Derived
* ControlServer implementations must call this at startup */
return TRUE;
}
void
_unref_worker(gpointer data)
{
ControlCommandThread *thread = (ControlCommandThread *) data;
msg_warning("Control command thread has not exited by the time we need to exit, forcing",
evt_tag_str("control_command", control_command_thread_get_command(thread)));
control_command_thread_unref(thread);
}
/* NOTE: this is called once the mainloop has exited, thus we would not get
* our worker_thread_finished() callbacks anymore. If our worker_threads is
* not empty at this point, then they have not yet responded to our cancel
* signal earlier and they won't as no further main loop iterations will be
* performed.
*
* At this point we can unref the elements of the worker list, the thread
* itself will keep a reference until it is done executing, but we won't get
* notifications anymore. If the thread is still running at the point
* _exit() is called, we would leak some ControlCommandThread instances.
*/
void
control_server_stop_method(ControlServer *self)
{
if (self->worker_threads)
{
g_list_free_full(self->worker_threads, _unref_worker);
self->worker_threads = NULL;
}
}
void
control_server_free_method(ControlServer *self)
{
}
void
control_server_init_instance(ControlServer *self)
{
self->worker_threads = NULL;
self->start = control_server_start_method;
self->stop = control_server_stop_method;
self->free_fn = control_server_free_method;
}
void
control_server_free(ControlServer *self)
{
g_assert(self->worker_threads == NULL);
if (self->free_fn)
{
self->free_fn(self);
}
g_free(self);
}
|