Run clang-format on the whole tree
[lttng-tools.git] / src / bin / lttng-sessiond / thread.cpp
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
c9e313bc 8#include "thread.hpp"
28ab034a
JG
9
10#include <common/defaults.hpp>
11#include <common/error.hpp>
12#include <common/macros.hpp>
13
14#include <pthread.h>
b878f05a
JG
15#include <urcu/list.h>
16#include <urcu/ref.h>
b878f05a 17
f1494934
JG
18namespace {
19struct thread_list {
b878f05a
JG
20 struct cds_list_head head;
21 pthread_mutex_t lock;
22} thread_list = {
23 .head = CDS_LIST_HEAD_INIT(thread_list.head),
24 .lock = PTHREAD_MUTEX_INITIALIZER,
25};
f1494934 26} /* namespace */
b878f05a
JG
27
28struct lttng_thread {
29 struct urcu_ref ref;
30 struct cds_list_head node;
31 pthread_t thread;
32 const char *name;
33 /* Main thread function */
34 lttng_thread_entry_point entry;
35 /*
36 * Thread-specific shutdown method. Allows threads to implement their
37 * own shutdown mechanism as some of them use a structured message
38 * passed through a command queue and some rely on a dedicated "quit"
39 * pipe.
40 */
41 lttng_thread_shutdown_cb shutdown;
42 lttng_thread_cleanup_cb cleanup;
43 /* Thread implementation-specific data. */
44 void *data;
45};
46
28ab034a 47static void lttng_thread_destroy(struct lttng_thread *thread)
b878f05a
JG
48{
49 if (thread->cleanup) {
50 thread->cleanup(thread->data);
51 }
52 free(thread);
53}
54
28ab034a 55static void lttng_thread_release(struct urcu_ref *ref)
b878f05a 56{
0114db0e 57 lttng_thread_destroy(lttng::utils::container_of(ref, &lttng_thread::ref));
b878f05a
JG
58}
59
28ab034a 60static void *launch_thread(void *data)
b878f05a
JG
61{
62 void *ret;
63 struct lttng_thread *thread = (struct lttng_thread *) data;
64
f5fb86c1
JG
65 logger_set_thread_name(thread->name, true);
66 DBG("Entering thread entry point");
b878f05a 67 ret = thread->entry(thread->data);
f5fb86c1 68 DBG("Thread entry point has returned");
b878f05a
JG
69 return ret;
70}
71
72struct lttng_thread *lttng_thread_create(const char *name,
28ab034a
JG
73 lttng_thread_entry_point entry,
74 lttng_thread_shutdown_cb shutdown,
75 lttng_thread_cleanup_cb cleanup,
76 void *thread_data)
b878f05a
JG
77{
78 int ret;
79 struct lttng_thread *thread;
80
64803277 81 thread = zmalloc<lttng_thread>();
b878f05a 82 if (!thread) {
21fa020e 83 goto error_alloc;
b878f05a
JG
84 }
85
86 urcu_ref_init(&thread->ref);
87 CDS_INIT_LIST_HEAD(&thread->node);
88 /*
89 * Thread names are assumed to be statically allocated strings.
90 * It is unnecessary to copy this attribute.
91 */
92 thread->name = name;
93 thread->entry = entry;
94 thread->shutdown = shutdown;
95 thread->cleanup = cleanup;
96 thread->data = thread_data;
97
98 pthread_mutex_lock(&thread_list.lock);
99 /*
100 * Add the thread at the head of the list to shutdown threads in the
101 * opposite order of their creation. A reference is taken for the
102 * thread list which will be released on shutdown of the thread.
103 */
104 cds_list_add(&thread->node, &thread_list.head);
105 (void) lttng_thread_get(thread);
106
28ab034a 107 ret = pthread_create(&thread->thread, default_pthread_attr(), launch_thread, thread);
b878f05a
JG
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 }
a0377dfe 137 LTTNG_ASSERT(thread->ref.refcount);
b878f05a
JG
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
28ab034a 146static bool _lttng_thread_shutdown(struct lttng_thread *thread)
b878f05a
JG
147{
148 int ret;
149 void *status;
150 bool result = true;
151
152 DBG("Shutting down \"%s\" thread", thread->name);
153 if (thread->shutdown) {
154 result = thread->shutdown(thread->data);
155 if (!result) {
156 result = false;
157 goto end;
158 }
159 }
160
161 ret = pthread_join(thread->thread, &status);
162 if (ret) {
163 PERROR("Failed to join \"%s\" thread", thread->name);
164 result = false;
19d3c73e 165 goto end;
b878f05a 166 }
f2b3ef9f 167 DBG("Joined thread \"%s\"", thread->name);
b878f05a
JG
168end:
169 return result;
170}
171
172bool lttng_thread_shutdown(struct lttng_thread *thread)
173{
f2b3ef9f
JG
174 const bool result = _lttng_thread_shutdown(thread);
175
176 if (result) {
177 /* Release the list's reference to the thread. */
178 pthread_mutex_lock(&thread_list.lock);
179 cds_list_del(&thread->node);
180 lttng_thread_put(thread);
181 pthread_mutex_unlock(&thread_list.lock);
182 }
b878f05a
JG
183 return result;
184}
185
186void lttng_thread_list_shutdown_orphans(void)
187{
188 struct lttng_thread *thread, *tmp;
189
190 pthread_mutex_lock(&thread_list.lock);
28ab034a 191 cds_list_for_each_entry_safe (thread, tmp, &thread_list.head, node) {
b878f05a
JG
192 bool result;
193 const long ref = uatomic_read(&thread->ref.refcount);
194
195 if (ref != 1) {
196 /*
197 * Other external references to the thread exist, skip.
198 */
199 continue;
200 }
201
202 result = _lttng_thread_shutdown(thread);
203 if (!result) {
204 ERR("Failed to shutdown thread \"%s\"", thread->name);
205 }
206 }
207 pthread_mutex_unlock(&thread_list.lock);
208}
This page took 0.060227 seconds and 4 git commands to generate.