sessiond: clarify the role of notification credentials
[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
64 DBG("Launching \"%s\" thread", thread->name);
65 ret = thread->entry(thread->data);
66 DBG("Thread \"%s\" has returned", thread->name);
67 return ret;
68}
69
70struct lttng_thread *lttng_thread_create(const char *name,
71 lttng_thread_entry_point entry,
72 lttng_thread_shutdown_cb shutdown,
73 lttng_thread_cleanup_cb cleanup,
74 void *thread_data)
75{
76 int ret;
77 struct lttng_thread *thread;
78
79 thread = zmalloc(sizeof(*thread));
80 if (!thread) {
21fa020e 81 goto error_alloc;
b878f05a
JG
82 }
83
84 urcu_ref_init(&thread->ref);
85 CDS_INIT_LIST_HEAD(&thread->node);
86 /*
87 * Thread names are assumed to be statically allocated strings.
88 * It is unnecessary to copy this attribute.
89 */
90 thread->name = name;
91 thread->entry = entry;
92 thread->shutdown = shutdown;
93 thread->cleanup = cleanup;
94 thread->data = thread_data;
95
96 pthread_mutex_lock(&thread_list.lock);
97 /*
98 * Add the thread at the head of the list to shutdown threads in the
99 * opposite order of their creation. A reference is taken for the
100 * thread list which will be released on shutdown of the thread.
101 */
102 cds_list_add(&thread->node, &thread_list.head);
103 (void) lttng_thread_get(thread);
104
105 ret = pthread_create(&thread->thread, default_pthread_attr(),
106 launch_thread, thread);
107 if (ret) {
108 PERROR("Failed to create \"%s\" thread", thread->name);
109 goto error_pthread_create;
110 }
111
112 pthread_mutex_unlock(&thread_list.lock);
113 return thread;
114
115error_pthread_create:
116 cds_list_del(&thread->node);
117 /* Release list reference. */
118 lttng_thread_put(thread);
119 pthread_mutex_unlock(&thread_list.lock);
b878f05a
JG
120 /* Release initial reference. */
121 lttng_thread_put(thread);
21fa020e 122error_alloc:
b878f05a
JG
123 return NULL;
124}
125
126bool lttng_thread_get(struct lttng_thread *thread)
127{
128 return urcu_ref_get_unless_zero(&thread->ref);
129}
130
131void lttng_thread_put(struct lttng_thread *thread)
132{
0f68efb6
JG
133 if (!thread) {
134 return;
135 }
b878f05a
JG
136 assert(thread->ref.refcount);
137 urcu_ref_put(&thread->ref, lttng_thread_release);
138}
139
140const char *lttng_thread_get_name(const struct lttng_thread *thread)
141{
142 return thread->name;
143}
144
145static
146bool _lttng_thread_shutdown(struct lttng_thread *thread)
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
JG
166 }
167 /* Release the list's reference to the thread. */
168 cds_list_del(&thread->node);
169 lttng_thread_put(thread);
170end:
171 return result;
172}
173
174bool lttng_thread_shutdown(struct lttng_thread *thread)
175{
176 bool result;
177
178 pthread_mutex_lock(&thread_list.lock);
179 result = _lttng_thread_shutdown(thread);
180 pthread_mutex_unlock(&thread_list.lock);
181 return result;
182}
183
184void lttng_thread_list_shutdown_orphans(void)
185{
186 struct lttng_thread *thread, *tmp;
187
188 pthread_mutex_lock(&thread_list.lock);
189 cds_list_for_each_entry_safe(thread, tmp, &thread_list.head, node) {
190 bool result;
191 const long ref = uatomic_read(&thread->ref.refcount);
192
193 if (ref != 1) {
194 /*
195 * Other external references to the thread exist, skip.
196 */
197 continue;
198 }
199
200 result = _lttng_thread_shutdown(thread);
201 if (!result) {
202 ERR("Failed to shutdown thread \"%s\"", thread->name);
203 }
204 }
205 pthread_mutex_unlock(&thread_list.lock);
206}
This page took 0.03585 seconds and 4 git commands to generate.