1a9643ea8Slogwang /*
2*d30ea906Sjfb8856606 * SPDX-License-Identifier: BSD-3-Clause
3*d30ea906Sjfb8856606 * Copyright 2015 Intel Corporation.
4*d30ea906Sjfb8856606 * Copyright 2012 Hasan Alayli <[email protected]>
5a9643ea8Slogwang */
6a9643ea8Slogwang
7a9643ea8Slogwang #define RTE_MEM 1
8a9643ea8Slogwang
9a9643ea8Slogwang #include <stdio.h>
10a9643ea8Slogwang #include <stdlib.h>
11a9643ea8Slogwang #include <string.h>
12a9643ea8Slogwang #include <stdint.h>
13a9643ea8Slogwang #include <stddef.h>
14a9643ea8Slogwang #include <limits.h>
15a9643ea8Slogwang #include <inttypes.h>
16a9643ea8Slogwang #include <unistd.h>
17a9643ea8Slogwang #include <pthread.h>
18a9643ea8Slogwang #include <fcntl.h>
19a9643ea8Slogwang #include <sys/time.h>
20a9643ea8Slogwang #include <sys/mman.h>
21a9643ea8Slogwang
22a9643ea8Slogwang #include <rte_log.h>
23a9643ea8Slogwang #include <ctx.h>
242bfe3f2eSlogwang #include <stack.h>
25a9643ea8Slogwang
26a9643ea8Slogwang #include "lthread_api.h"
27a9643ea8Slogwang #include "lthread.h"
28a9643ea8Slogwang #include "lthread_timer.h"
29a9643ea8Slogwang #include "lthread_tls.h"
30a9643ea8Slogwang #include "lthread_objcache.h"
31a9643ea8Slogwang #include "lthread_diag.h"
32a9643ea8Slogwang
33a9643ea8Slogwang
34a9643ea8Slogwang /*
35a9643ea8Slogwang * This function gets called after an lthread function has returned.
36a9643ea8Slogwang */
_lthread_exit_handler(struct lthread * lt)37a9643ea8Slogwang void _lthread_exit_handler(struct lthread *lt)
38a9643ea8Slogwang {
39a9643ea8Slogwang
40a9643ea8Slogwang lt->state |= BIT(ST_LT_EXITED);
41a9643ea8Slogwang
42a9643ea8Slogwang if (!(lt->state & BIT(ST_LT_DETACH))) {
43a9643ea8Slogwang /* thread is this not explicitly detached
44a9643ea8Slogwang * it must be joinable, so we call lthread_exit().
45a9643ea8Slogwang */
46a9643ea8Slogwang lthread_exit(NULL);
47a9643ea8Slogwang }
48a9643ea8Slogwang
49a9643ea8Slogwang /* if we get here the thread is detached so we can reschedule it,
50a9643ea8Slogwang * allowing the scheduler to free it
51a9643ea8Slogwang */
52a9643ea8Slogwang _reschedule();
53a9643ea8Slogwang }
54a9643ea8Slogwang
55a9643ea8Slogwang
56a9643ea8Slogwang /*
57a9643ea8Slogwang * Free resources allocated to an lthread
58a9643ea8Slogwang */
_lthread_free(struct lthread * lt)59a9643ea8Slogwang void _lthread_free(struct lthread *lt)
60a9643ea8Slogwang {
61a9643ea8Slogwang
62a9643ea8Slogwang DIAG_EVENT(lt, LT_DIAG_LTHREAD_FREE, lt, 0);
63a9643ea8Slogwang
64a9643ea8Slogwang /* invoke any user TLS destructor functions */
65a9643ea8Slogwang _lthread_tls_destroy(lt);
66a9643ea8Slogwang
67a9643ea8Slogwang /* free memory allocated for TLS defined using RTE_PER_LTHREAD macros */
68a9643ea8Slogwang if (sizeof(void *) < (uint64_t)RTE_PER_LTHREAD_SECTION_SIZE)
69a9643ea8Slogwang _lthread_objcache_free(lt->tls->root_sched->per_lthread_cache,
70a9643ea8Slogwang lt->per_lthread_data);
71a9643ea8Slogwang
72a9643ea8Slogwang /* free pthread style TLS memory */
73a9643ea8Slogwang _lthread_objcache_free(lt->tls->root_sched->tls_cache, lt->tls);
74a9643ea8Slogwang
75a9643ea8Slogwang /* free the stack */
76a9643ea8Slogwang _lthread_objcache_free(lt->stack_container->root_sched->stack_cache,
77a9643ea8Slogwang lt->stack_container);
78a9643ea8Slogwang
79a9643ea8Slogwang /* now free the thread */
80a9643ea8Slogwang _lthread_objcache_free(lt->root_sched->lthread_cache, lt);
81a9643ea8Slogwang
82a9643ea8Slogwang }
83a9643ea8Slogwang
84a9643ea8Slogwang /*
85a9643ea8Slogwang * Allocate a stack and maintain a cache of stacks
86a9643ea8Slogwang */
_stack_alloc(void)87a9643ea8Slogwang struct lthread_stack *_stack_alloc(void)
88a9643ea8Slogwang {
89a9643ea8Slogwang struct lthread_stack *s;
90a9643ea8Slogwang
91a9643ea8Slogwang s = _lthread_objcache_alloc((THIS_SCHED)->stack_cache);
92a9643ea8Slogwang RTE_ASSERT(s != NULL);
93a9643ea8Slogwang
94a9643ea8Slogwang s->root_sched = THIS_SCHED;
95a9643ea8Slogwang s->stack_size = LTHREAD_MAX_STACK_SIZE;
96a9643ea8Slogwang return s;
97a9643ea8Slogwang }
98a9643ea8Slogwang
99a9643ea8Slogwang /*
100a9643ea8Slogwang * Execute a ctx by invoking the start function
101a9643ea8Slogwang * On return call an exit handler if the user has provided one
102a9643ea8Slogwang */
_lthread_exec(void * arg)103a9643ea8Slogwang static void _lthread_exec(void *arg)
104a9643ea8Slogwang {
105a9643ea8Slogwang struct lthread *lt = (struct lthread *)arg;
106a9643ea8Slogwang
107a9643ea8Slogwang /* invoke the contexts function */
108a9643ea8Slogwang lt->fun(lt->arg);
109a9643ea8Slogwang /* do exit handling */
110a9643ea8Slogwang if (lt->exit_handler != NULL)
111a9643ea8Slogwang lt->exit_handler(lt);
112a9643ea8Slogwang }
113a9643ea8Slogwang
114a9643ea8Slogwang /*
115a9643ea8Slogwang * Initialize an lthread
116a9643ea8Slogwang * Set its function, args, and exit handler
117a9643ea8Slogwang */
118a9643ea8Slogwang void
_lthread_init(struct lthread * lt,lthread_func_t fun,void * arg,lthread_exit_func exit_handler)119a9643ea8Slogwang _lthread_init(struct lthread *lt,
120a9643ea8Slogwang lthread_func_t fun, void *arg, lthread_exit_func exit_handler)
121a9643ea8Slogwang {
122a9643ea8Slogwang
123a9643ea8Slogwang /* set ctx func and args */
124a9643ea8Slogwang lt->fun = fun;
125a9643ea8Slogwang lt->arg = arg;
126a9643ea8Slogwang lt->exit_handler = exit_handler;
127a9643ea8Slogwang
128a9643ea8Slogwang /* set initial state */
129a9643ea8Slogwang lt->birth = _sched_now();
130a9643ea8Slogwang lt->state = BIT(ST_LT_INIT);
131a9643ea8Slogwang lt->join = LT_JOIN_INITIAL;
132a9643ea8Slogwang }
133a9643ea8Slogwang
134a9643ea8Slogwang /*
135a9643ea8Slogwang * set the lthread stack
136a9643ea8Slogwang */
_lthread_set_stack(struct lthread * lt,void * stack,size_t stack_size)137a9643ea8Slogwang void _lthread_set_stack(struct lthread *lt, void *stack, size_t stack_size)
138a9643ea8Slogwang {
139a9643ea8Slogwang /* set stack */
140a9643ea8Slogwang lt->stack = stack;
141a9643ea8Slogwang lt->stack_size = stack_size;
142a9643ea8Slogwang
1432bfe3f2eSlogwang arch_set_stack(lt, _lthread_exec);
144a9643ea8Slogwang }
145a9643ea8Slogwang
146a9643ea8Slogwang /*
147a9643ea8Slogwang * Create an lthread on the current scheduler
148a9643ea8Slogwang * If there is no current scheduler on this pthread then first create one
149a9643ea8Slogwang */
150a9643ea8Slogwang int
lthread_create(struct lthread ** new_lt,int lcore_id,lthread_func_t fun,void * arg)151a9643ea8Slogwang lthread_create(struct lthread **new_lt, int lcore_id,
152a9643ea8Slogwang lthread_func_t fun, void *arg)
153a9643ea8Slogwang {
154a9643ea8Slogwang if ((new_lt == NULL) || (fun == NULL))
155a9643ea8Slogwang return POSIX_ERRNO(EINVAL);
156a9643ea8Slogwang
157a9643ea8Slogwang if (lcore_id < 0)
158a9643ea8Slogwang lcore_id = rte_lcore_id();
159a9643ea8Slogwang else if (lcore_id > LTHREAD_MAX_LCORES)
160a9643ea8Slogwang return POSIX_ERRNO(EINVAL);
161a9643ea8Slogwang
162a9643ea8Slogwang struct lthread *lt = NULL;
163a9643ea8Slogwang
164a9643ea8Slogwang if (THIS_SCHED == NULL) {
165a9643ea8Slogwang THIS_SCHED = _lthread_sched_create(0);
166a9643ea8Slogwang if (THIS_SCHED == NULL) {
167a9643ea8Slogwang perror("Failed to create scheduler");
168a9643ea8Slogwang return POSIX_ERRNO(EAGAIN);
169a9643ea8Slogwang }
170a9643ea8Slogwang }
171a9643ea8Slogwang
172a9643ea8Slogwang /* allocate a thread structure */
173a9643ea8Slogwang lt = _lthread_objcache_alloc((THIS_SCHED)->lthread_cache);
174a9643ea8Slogwang if (lt == NULL)
175a9643ea8Slogwang return POSIX_ERRNO(EAGAIN);
176a9643ea8Slogwang
177a9643ea8Slogwang bzero(lt, sizeof(struct lthread));
178a9643ea8Slogwang lt->root_sched = THIS_SCHED;
179a9643ea8Slogwang
180a9643ea8Slogwang /* set the function args and exit handlder */
181a9643ea8Slogwang _lthread_init(lt, fun, arg, _lthread_exit_handler);
182a9643ea8Slogwang
183a9643ea8Slogwang /* put it in the ready queue */
184a9643ea8Slogwang *new_lt = lt;
185a9643ea8Slogwang
186a9643ea8Slogwang if (lcore_id < 0)
187a9643ea8Slogwang lcore_id = rte_lcore_id();
188a9643ea8Slogwang
189a9643ea8Slogwang DIAG_CREATE_EVENT(lt, LT_DIAG_LTHREAD_CREATE);
190a9643ea8Slogwang
191a9643ea8Slogwang rte_wmb();
192a9643ea8Slogwang _ready_queue_insert(_lthread_sched_get(lcore_id), lt);
193a9643ea8Slogwang return 0;
194a9643ea8Slogwang }
195a9643ea8Slogwang
196a9643ea8Slogwang /*
197a9643ea8Slogwang * Schedules lthread to sleep for `nsecs`
198a9643ea8Slogwang * setting the lthread state to LT_ST_SLEEPING.
199a9643ea8Slogwang * lthread state is cleared upon resumption or expiry.
200a9643ea8Slogwang */
_lthread_sched_sleep(struct lthread * lt,uint64_t nsecs)201a9643ea8Slogwang static inline void _lthread_sched_sleep(struct lthread *lt, uint64_t nsecs)
202a9643ea8Slogwang {
203a9643ea8Slogwang uint64_t state = lt->state;
204a9643ea8Slogwang uint64_t clks = _ns_to_clks(nsecs);
205a9643ea8Slogwang
206a9643ea8Slogwang if (clks) {
207a9643ea8Slogwang _timer_start(lt, clks);
208a9643ea8Slogwang lt->state = state | BIT(ST_LT_SLEEPING);
209a9643ea8Slogwang }
210a9643ea8Slogwang DIAG_EVENT(lt, LT_DIAG_LTHREAD_SLEEP, clks, 0);
211a9643ea8Slogwang _suspend();
212a9643ea8Slogwang }
213a9643ea8Slogwang
214a9643ea8Slogwang
215a9643ea8Slogwang
216a9643ea8Slogwang /*
217a9643ea8Slogwang * Cancels any running timer.
218a9643ea8Slogwang * This can be called multiple times on the same lthread regardless if it was
219a9643ea8Slogwang * sleeping or not.
220a9643ea8Slogwang */
_lthread_desched_sleep(struct lthread * lt)221a9643ea8Slogwang int _lthread_desched_sleep(struct lthread *lt)
222a9643ea8Slogwang {
223a9643ea8Slogwang uint64_t state = lt->state;
224a9643ea8Slogwang
225a9643ea8Slogwang if (state & BIT(ST_LT_SLEEPING)) {
226a9643ea8Slogwang _timer_stop(lt);
227a9643ea8Slogwang state &= (CLEARBIT(ST_LT_SLEEPING) & CLEARBIT(ST_LT_EXPIRED));
228a9643ea8Slogwang lt->state = state | BIT(ST_LT_READY);
229a9643ea8Slogwang return 1;
230a9643ea8Slogwang }
231a9643ea8Slogwang return 0;
232a9643ea8Slogwang }
233a9643ea8Slogwang
234a9643ea8Slogwang /*
235a9643ea8Slogwang * set user data pointer in an lthread
236a9643ea8Slogwang */
lthread_set_data(void * data)237a9643ea8Slogwang void lthread_set_data(void *data)
238a9643ea8Slogwang {
239a9643ea8Slogwang if (sizeof(void *) == RTE_PER_LTHREAD_SECTION_SIZE)
240a9643ea8Slogwang THIS_LTHREAD->per_lthread_data = data;
241a9643ea8Slogwang }
242a9643ea8Slogwang
243a9643ea8Slogwang /*
244a9643ea8Slogwang * Retrieve user data pointer from an lthread
245a9643ea8Slogwang */
lthread_get_data(void)246a9643ea8Slogwang void *lthread_get_data(void)
247a9643ea8Slogwang {
248a9643ea8Slogwang return THIS_LTHREAD->per_lthread_data;
249a9643ea8Slogwang }
250a9643ea8Slogwang
251a9643ea8Slogwang /*
252a9643ea8Slogwang * Return the current lthread handle
253a9643ea8Slogwang */
lthread_current(void)254a9643ea8Slogwang struct lthread *lthread_current(void)
255a9643ea8Slogwang {
256a9643ea8Slogwang struct lthread_sched *sched = THIS_SCHED;
257a9643ea8Slogwang
258a9643ea8Slogwang if (sched)
259a9643ea8Slogwang return sched->current_lthread;
260a9643ea8Slogwang return NULL;
261a9643ea8Slogwang }
262a9643ea8Slogwang
263a9643ea8Slogwang
264a9643ea8Slogwang
265a9643ea8Slogwang /*
266a9643ea8Slogwang * Tasklet to cancel a thread
267a9643ea8Slogwang */
268579bf1e2Sjfb8856606 static void *
_cancel(void * arg)269a9643ea8Slogwang _cancel(void *arg)
270a9643ea8Slogwang {
271a9643ea8Slogwang struct lthread *lt = (struct lthread *) arg;
272a9643ea8Slogwang
273a9643ea8Slogwang lt->state |= BIT(ST_LT_CANCELLED);
274a9643ea8Slogwang lthread_detach();
275579bf1e2Sjfb8856606 return NULL;
276a9643ea8Slogwang }
277a9643ea8Slogwang
278a9643ea8Slogwang
279a9643ea8Slogwang /*
280a9643ea8Slogwang * Mark the specified as canceled
281a9643ea8Slogwang */
lthread_cancel(struct lthread * cancel_lt)282a9643ea8Slogwang int lthread_cancel(struct lthread *cancel_lt)
283a9643ea8Slogwang {
284a9643ea8Slogwang struct lthread *lt;
285a9643ea8Slogwang
286a9643ea8Slogwang if ((cancel_lt == NULL) || (cancel_lt == THIS_LTHREAD))
287a9643ea8Slogwang return POSIX_ERRNO(EINVAL);
288a9643ea8Slogwang
289a9643ea8Slogwang DIAG_EVENT(cancel_lt, LT_DIAG_LTHREAD_CANCEL, cancel_lt, 0);
290a9643ea8Slogwang
291a9643ea8Slogwang if (cancel_lt->sched != THIS_SCHED) {
292a9643ea8Slogwang
293a9643ea8Slogwang /* spawn task-let to cancel the thread */
294a9643ea8Slogwang lthread_create(<,
295a9643ea8Slogwang cancel_lt->sched->lcore_id,
296a9643ea8Slogwang _cancel,
297a9643ea8Slogwang cancel_lt);
298a9643ea8Slogwang return 0;
299a9643ea8Slogwang }
300a9643ea8Slogwang cancel_lt->state |= BIT(ST_LT_CANCELLED);
301a9643ea8Slogwang return 0;
302a9643ea8Slogwang }
303a9643ea8Slogwang
304a9643ea8Slogwang /*
305a9643ea8Slogwang * Suspend the current lthread for specified time
306a9643ea8Slogwang */
lthread_sleep(uint64_t nsecs)307a9643ea8Slogwang void lthread_sleep(uint64_t nsecs)
308a9643ea8Slogwang {
309a9643ea8Slogwang struct lthread *lt = THIS_LTHREAD;
310a9643ea8Slogwang
311a9643ea8Slogwang _lthread_sched_sleep(lt, nsecs);
312a9643ea8Slogwang
313a9643ea8Slogwang }
314a9643ea8Slogwang
315a9643ea8Slogwang /*
316a9643ea8Slogwang * Suspend the current lthread for specified time
317a9643ea8Slogwang */
lthread_sleep_clks(uint64_t clks)318a9643ea8Slogwang void lthread_sleep_clks(uint64_t clks)
319a9643ea8Slogwang {
320a9643ea8Slogwang struct lthread *lt = THIS_LTHREAD;
321a9643ea8Slogwang uint64_t state = lt->state;
322a9643ea8Slogwang
323a9643ea8Slogwang if (clks) {
324a9643ea8Slogwang _timer_start(lt, clks);
325a9643ea8Slogwang lt->state = state | BIT(ST_LT_SLEEPING);
326a9643ea8Slogwang }
327a9643ea8Slogwang DIAG_EVENT(lt, LT_DIAG_LTHREAD_SLEEP, clks, 0);
328a9643ea8Slogwang _suspend();
329a9643ea8Slogwang }
330a9643ea8Slogwang
331a9643ea8Slogwang /*
332a9643ea8Slogwang * Requeue the current thread to the back of the ready queue
333a9643ea8Slogwang */
lthread_yield(void)334a9643ea8Slogwang void lthread_yield(void)
335a9643ea8Slogwang {
336a9643ea8Slogwang struct lthread *lt = THIS_LTHREAD;
337a9643ea8Slogwang
338a9643ea8Slogwang DIAG_EVENT(lt, LT_DIAG_LTHREAD_YIELD, 0, 0);
339a9643ea8Slogwang
340a9643ea8Slogwang _ready_queue_insert(THIS_SCHED, lt);
341a9643ea8Slogwang ctx_switch(&(THIS_SCHED)->ctx, <->ctx);
342a9643ea8Slogwang }
343a9643ea8Slogwang
344a9643ea8Slogwang /*
345a9643ea8Slogwang * Exit the current lthread
346a9643ea8Slogwang * If a thread is joining pass the user pointer to it
347a9643ea8Slogwang */
lthread_exit(void * ptr)348a9643ea8Slogwang void lthread_exit(void *ptr)
349a9643ea8Slogwang {
350a9643ea8Slogwang struct lthread *lt = THIS_LTHREAD;
351a9643ea8Slogwang
352a9643ea8Slogwang /* if thread is detached (this is not valid) just exit */
353a9643ea8Slogwang if (lt->state & BIT(ST_LT_DETACH))
354a9643ea8Slogwang return;
355a9643ea8Slogwang
356a9643ea8Slogwang /* There is a race between lthread_join() and lthread_exit()
357a9643ea8Slogwang * - if exit before join then we suspend and resume on join
358a9643ea8Slogwang * - if join before exit then we resume the joining thread
359a9643ea8Slogwang */
360a9643ea8Slogwang if ((lt->join == LT_JOIN_INITIAL)
361a9643ea8Slogwang && rte_atomic64_cmpset(<->join, LT_JOIN_INITIAL,
362a9643ea8Slogwang LT_JOIN_EXITING)) {
363a9643ea8Slogwang
364a9643ea8Slogwang DIAG_EVENT(lt, LT_DIAG_LTHREAD_EXIT, 1, 0);
365a9643ea8Slogwang _suspend();
366a9643ea8Slogwang /* set the exit value */
367a9643ea8Slogwang if ((ptr != NULL) && (lt->lt_join->lt_exit_ptr != NULL))
368a9643ea8Slogwang *(lt->lt_join->lt_exit_ptr) = ptr;
369a9643ea8Slogwang
370a9643ea8Slogwang /* let the joining thread know we have set the exit value */
371a9643ea8Slogwang lt->join = LT_JOIN_EXIT_VAL_SET;
372a9643ea8Slogwang } else {
373a9643ea8Slogwang
374a9643ea8Slogwang DIAG_EVENT(lt, LT_DIAG_LTHREAD_EXIT, 0, 0);
375a9643ea8Slogwang /* set the exit value */
376a9643ea8Slogwang if ((ptr != NULL) && (lt->lt_join->lt_exit_ptr != NULL))
377a9643ea8Slogwang *(lt->lt_join->lt_exit_ptr) = ptr;
378a9643ea8Slogwang /* let the joining thread know we have set the exit value */
379a9643ea8Slogwang lt->join = LT_JOIN_EXIT_VAL_SET;
380a9643ea8Slogwang _ready_queue_insert(lt->lt_join->sched,
381a9643ea8Slogwang (struct lthread *)lt->lt_join);
382a9643ea8Slogwang }
383a9643ea8Slogwang
384a9643ea8Slogwang
385a9643ea8Slogwang /* wait until the joinging thread has collected the exit value */
386a9643ea8Slogwang while (lt->join != LT_JOIN_EXIT_VAL_READ)
387a9643ea8Slogwang _reschedule();
388a9643ea8Slogwang
389a9643ea8Slogwang /* reset join state */
390a9643ea8Slogwang lt->join = LT_JOIN_INITIAL;
391a9643ea8Slogwang
392a9643ea8Slogwang /* detach it so its resources can be released */
393a9643ea8Slogwang lt->state |= (BIT(ST_LT_DETACH) | BIT(ST_LT_EXITED));
394a9643ea8Slogwang }
395a9643ea8Slogwang
396a9643ea8Slogwang /*
397a9643ea8Slogwang * Join an lthread
398a9643ea8Slogwang * Suspend until the joined thread returns
399a9643ea8Slogwang */
lthread_join(struct lthread * lt,void ** ptr)400a9643ea8Slogwang int lthread_join(struct lthread *lt, void **ptr)
401a9643ea8Slogwang {
402a9643ea8Slogwang if (lt == NULL)
403a9643ea8Slogwang return POSIX_ERRNO(EINVAL);
404a9643ea8Slogwang
405a9643ea8Slogwang struct lthread *current = THIS_LTHREAD;
406a9643ea8Slogwang uint64_t lt_state = lt->state;
407a9643ea8Slogwang
408a9643ea8Slogwang /* invalid to join a detached thread, or a thread that is joined */
409a9643ea8Slogwang if ((lt_state & BIT(ST_LT_DETACH)) || (lt->join == LT_JOIN_THREAD_SET))
410a9643ea8Slogwang return POSIX_ERRNO(EINVAL);
411a9643ea8Slogwang /* pointer to the joining thread and a poingter to return a value */
412a9643ea8Slogwang lt->lt_join = current;
413a9643ea8Slogwang current->lt_exit_ptr = ptr;
414a9643ea8Slogwang /* There is a race between lthread_join() and lthread_exit()
415a9643ea8Slogwang * - if join before exit we suspend and will resume when exit is called
416a9643ea8Slogwang * - if exit before join we resume the exiting thread
417a9643ea8Slogwang */
418a9643ea8Slogwang if ((lt->join == LT_JOIN_INITIAL)
419a9643ea8Slogwang && rte_atomic64_cmpset(<->join, LT_JOIN_INITIAL,
420a9643ea8Slogwang LT_JOIN_THREAD_SET)) {
421a9643ea8Slogwang
422a9643ea8Slogwang DIAG_EVENT(current, LT_DIAG_LTHREAD_JOIN, lt, 1);
423a9643ea8Slogwang _suspend();
424a9643ea8Slogwang } else {
425a9643ea8Slogwang DIAG_EVENT(current, LT_DIAG_LTHREAD_JOIN, lt, 0);
426a9643ea8Slogwang _ready_queue_insert(lt->sched, lt);
427a9643ea8Slogwang }
428a9643ea8Slogwang
429a9643ea8Slogwang /* wait for exiting thread to set return value */
430a9643ea8Slogwang while (lt->join != LT_JOIN_EXIT_VAL_SET)
431a9643ea8Slogwang _reschedule();
432a9643ea8Slogwang
433a9643ea8Slogwang /* collect the return value */
434a9643ea8Slogwang if (ptr != NULL)
435a9643ea8Slogwang *ptr = *current->lt_exit_ptr;
436a9643ea8Slogwang
437a9643ea8Slogwang /* let the exiting thread proceed to exit */
438a9643ea8Slogwang lt->join = LT_JOIN_EXIT_VAL_READ;
439a9643ea8Slogwang return 0;
440a9643ea8Slogwang }
441a9643ea8Slogwang
442a9643ea8Slogwang
443a9643ea8Slogwang /*
444a9643ea8Slogwang * Detach current lthread
445a9643ea8Slogwang * A detached thread cannot be joined
446a9643ea8Slogwang */
lthread_detach(void)447a9643ea8Slogwang void lthread_detach(void)
448a9643ea8Slogwang {
449a9643ea8Slogwang struct lthread *lt = THIS_LTHREAD;
450a9643ea8Slogwang
451a9643ea8Slogwang DIAG_EVENT(lt, LT_DIAG_LTHREAD_DETACH, 0, 0);
452a9643ea8Slogwang
453a9643ea8Slogwang uint64_t state = lt->state;
454a9643ea8Slogwang
455a9643ea8Slogwang lt->state = state | BIT(ST_LT_DETACH);
456a9643ea8Slogwang }
457a9643ea8Slogwang
458a9643ea8Slogwang /*
459a9643ea8Slogwang * Set function name of an lthread
460a9643ea8Slogwang * this is a debug aid
461a9643ea8Slogwang */
lthread_set_funcname(const char * f)462a9643ea8Slogwang void lthread_set_funcname(const char *f)
463a9643ea8Slogwang {
464a9643ea8Slogwang struct lthread *lt = THIS_LTHREAD;
465a9643ea8Slogwang
466a9643ea8Slogwang strncpy(lt->funcname, f, sizeof(lt->funcname));
467a9643ea8Slogwang lt->funcname[sizeof(lt->funcname)-1] = 0;
468a9643ea8Slogwang }
469