Fix: sessiond: client socket not created by the main thread
[lttng-tools.git] / src / bin / lttng-sessiond / thread.c
1 /*
2 * Copyright (C) 2018 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License, version 2 only, as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 51
15 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17
18 #include "thread.h"
19 #include <urcu/list.h>
20 #include <urcu/ref.h>
21 #include <pthread.h>
22 #include <common/macros.h>
23 #include <common/error.h>
24 #include <common/defaults.h>
25
26 static struct thread_list {
27 struct cds_list_head head;
28 pthread_mutex_t lock;
29 } thread_list = {
30 .head = CDS_LIST_HEAD_INIT(thread_list.head),
31 .lock = PTHREAD_MUTEX_INITIALIZER,
32 };
33
34 struct lttng_thread {
35 struct urcu_ref ref;
36 struct cds_list_head node;
37 pthread_t thread;
38 const char *name;
39 /* Main thread function */
40 lttng_thread_entry_point entry;
41 /*
42 * Thread-specific shutdown method. Allows threads to implement their
43 * own shutdown mechanism as some of them use a structured message
44 * passed through a command queue and some rely on a dedicated "quit"
45 * pipe.
46 */
47 lttng_thread_shutdown_cb shutdown;
48 lttng_thread_cleanup_cb cleanup;
49 /* Thread implementation-specific data. */
50 void *data;
51 };
52
53 static
54 void lttng_thread_destroy(struct lttng_thread *thread)
55 {
56 if (thread->cleanup) {
57 thread->cleanup(thread->data);
58 }
59 free(thread);
60 }
61
62 static
63 void lttng_thread_release(struct urcu_ref *ref)
64 {
65 lttng_thread_destroy(container_of(ref, struct lttng_thread, ref));
66 }
67
68 static
69 void *launch_thread(void *data)
70 {
71 void *ret;
72 struct lttng_thread *thread = (struct lttng_thread *) data;
73
74 DBG("Launching \"%s\" thread", thread->name);
75 ret = thread->entry(thread->data);
76 DBG("Thread \"%s\" has returned", thread->name);
77 return ret;
78 }
79
80 struct lttng_thread *lttng_thread_create(const char *name,
81 lttng_thread_entry_point entry,
82 lttng_thread_shutdown_cb shutdown,
83 lttng_thread_cleanup_cb cleanup,
84 void *thread_data)
85 {
86 int ret;
87 struct lttng_thread *thread;
88
89 thread = zmalloc(sizeof(*thread));
90 if (!thread) {
91 goto error_alloc;
92 }
93
94 urcu_ref_init(&thread->ref);
95 CDS_INIT_LIST_HEAD(&thread->node);
96 /*
97 * Thread names are assumed to be statically allocated strings.
98 * It is unnecessary to copy this attribute.
99 */
100 thread->name = name;
101 thread->entry = entry;
102 thread->shutdown = shutdown;
103 thread->cleanup = cleanup;
104 thread->data = thread_data;
105
106 pthread_mutex_lock(&thread_list.lock);
107 /*
108 * Add the thread at the head of the list to shutdown threads in the
109 * opposite order of their creation. A reference is taken for the
110 * thread list which will be released on shutdown of the thread.
111 */
112 cds_list_add(&thread->node, &thread_list.head);
113 (void) lttng_thread_get(thread);
114
115 ret = pthread_create(&thread->thread, default_pthread_attr(),
116 launch_thread, thread);
117 if (ret) {
118 PERROR("Failed to create \"%s\" thread", thread->name);
119 goto error_pthread_create;
120 }
121
122 pthread_mutex_unlock(&thread_list.lock);
123 return thread;
124
125 error_pthread_create:
126 cds_list_del(&thread->node);
127 /* Release list reference. */
128 lttng_thread_put(thread);
129 pthread_mutex_unlock(&thread_list.lock);
130 /* Release initial reference. */
131 lttng_thread_put(thread);
132 error_alloc:
133 return NULL;
134 }
135
136 bool lttng_thread_get(struct lttng_thread *thread)
137 {
138 return urcu_ref_get_unless_zero(&thread->ref);
139 }
140
141 void lttng_thread_put(struct lttng_thread *thread)
142 {
143 if (!thread) {
144 return;
145 }
146 assert(thread->ref.refcount);
147 urcu_ref_put(&thread->ref, lttng_thread_release);
148 }
149
150 const char *lttng_thread_get_name(const struct lttng_thread *thread)
151 {
152 return thread->name;
153 }
154
155 static
156 bool _lttng_thread_shutdown(struct lttng_thread *thread)
157 {
158 int ret;
159 void *status;
160 bool result = true;
161
162 DBG("Shutting down \"%s\" thread", thread->name);
163 if (thread->shutdown) {
164 result = thread->shutdown(thread->data);
165 if (!result) {
166 result = false;
167 goto end;
168 }
169 }
170
171 ret = pthread_join(thread->thread, &status);
172 if (ret) {
173 PERROR("Failed to join \"%s\" thread", thread->name);
174 result = false;
175 goto end;
176 }
177 /* Release the list's reference to the thread. */
178 cds_list_del(&thread->node);
179 lttng_thread_put(thread);
180 end:
181 return result;
182 }
183
184 bool lttng_thread_shutdown(struct lttng_thread *thread)
185 {
186 bool result;
187
188 pthread_mutex_lock(&thread_list.lock);
189 result = _lttng_thread_shutdown(thread);
190 pthread_mutex_unlock(&thread_list.lock);
191 return result;
192 }
193
194 void lttng_thread_list_shutdown_orphans(void)
195 {
196 struct lttng_thread *thread, *tmp;
197
198 pthread_mutex_lock(&thread_list.lock);
199 cds_list_for_each_entry_safe(thread, tmp, &thread_list.head, node) {
200 bool result;
201 const long ref = uatomic_read(&thread->ref.refcount);
202
203 if (ref != 1) {
204 /*
205 * Other external references to the thread exist, skip.
206 */
207 continue;
208 }
209
210 result = _lttng_thread_shutdown(thread);
211 if (!result) {
212 ERR("Failed to shutdown thread \"%s\"", thread->name);
213 }
214 }
215 pthread_mutex_unlock(&thread_list.lock);
216 }
This page took 0.051649 seconds and 6 git commands to generate.