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