2 * Copyright (C) 2018 Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 * SPDX-License-Identifier: GPL-2.0-only
12 #include <common/macros.h>
13 #include <common/error.h>
14 #include <common/defaults.h>
16 static struct thread_list
{
17 struct cds_list_head head
;
20 .head
= CDS_LIST_HEAD_INIT(thread_list
.head
),
21 .lock
= PTHREAD_MUTEX_INITIALIZER
,
26 struct cds_list_head node
;
29 /* Main thread function */
30 lttng_thread_entry_point entry
;
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"
37 lttng_thread_shutdown_cb shutdown
;
38 lttng_thread_cleanup_cb cleanup
;
39 /* Thread implementation-specific data. */
44 void lttng_thread_destroy(struct lttng_thread
*thread
)
46 if (thread
->cleanup
) {
47 thread
->cleanup(thread
->data
);
53 void lttng_thread_release(struct urcu_ref
*ref
)
55 lttng_thread_destroy(container_of(ref
, struct lttng_thread
, ref
));
59 void *launch_thread(void *data
)
62 struct lttng_thread
*thread
= (struct lttng_thread
*) data
;
64 DBG("Launching \"%s\" thread", thread
->name
);
65 ret
= thread
->entry(thread
->data
);
66 DBG("Thread \"%s\" has returned", thread
->name
);
70 struct 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
,
77 struct lttng_thread
*thread
;
79 thread
= zmalloc(sizeof(*thread
));
84 urcu_ref_init(&thread
->ref
);
85 CDS_INIT_LIST_HEAD(&thread
->node
);
87 * Thread names are assumed to be statically allocated strings.
88 * It is unnecessary to copy this attribute.
91 thread
->entry
= entry
;
92 thread
->shutdown
= shutdown
;
93 thread
->cleanup
= cleanup
;
94 thread
->data
= thread_data
;
96 pthread_mutex_lock(&thread_list
.lock
);
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.
102 cds_list_add(&thread
->node
, &thread_list
.head
);
103 (void) lttng_thread_get(thread
);
105 ret
= pthread_create(&thread
->thread
, default_pthread_attr(),
106 launch_thread
, thread
);
108 PERROR("Failed to create \"%s\" thread", thread
->name
);
109 goto error_pthread_create
;
112 pthread_mutex_unlock(&thread_list
.lock
);
115 error_pthread_create
:
116 cds_list_del(&thread
->node
);
117 /* Release list reference. */
118 lttng_thread_put(thread
);
119 pthread_mutex_unlock(&thread_list
.lock
);
120 /* Release initial reference. */
121 lttng_thread_put(thread
);
126 bool lttng_thread_get(struct lttng_thread
*thread
)
128 return urcu_ref_get_unless_zero(&thread
->ref
);
131 void lttng_thread_put(struct lttng_thread
*thread
)
136 assert(thread
->ref
.refcount
);
137 urcu_ref_put(&thread
->ref
, lttng_thread_release
);
140 const char *lttng_thread_get_name(const struct lttng_thread
*thread
)
146 bool _lttng_thread_shutdown(struct lttng_thread
*thread
)
152 DBG("Shutting down \"%s\" thread", thread
->name
);
153 if (thread
->shutdown
) {
154 result
= thread
->shutdown(thread
->data
);
161 ret
= pthread_join(thread
->thread
, &status
);
163 PERROR("Failed to join \"%s\" thread", thread
->name
);
167 /* Release the list's reference to the thread. */
168 cds_list_del(&thread
->node
);
169 lttng_thread_put(thread
);
174 bool lttng_thread_shutdown(struct lttng_thread
*thread
)
178 pthread_mutex_lock(&thread_list
.lock
);
179 result
= _lttng_thread_shutdown(thread
);
180 pthread_mutex_unlock(&thread_list
.lock
);
184 void lttng_thread_list_shutdown_orphans(void)
186 struct lttng_thread
*thread
, *tmp
;
188 pthread_mutex_lock(&thread_list
.lock
);
189 cds_list_for_each_entry_safe(thread
, tmp
, &thread_list
.head
, node
) {
191 const long ref
= uatomic_read(&thread
->ref
.refcount
);
195 * Other external references to the thread exist, skip.
200 result
= _lttng_thread_shutdown(thread
);
202 ERR("Failed to shutdown thread \"%s\"", thread
->name
);
205 pthread_mutex_unlock(&thread_list
.lock
);