source: mainline/uspace/lib/c/generic/thread.c@ 6bb136b2

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 6bb136b2 was 514d561, checked in by Jiří Zárevúcky <jiri.zarevucky@…>, 7 years ago

Fibril/async implementation overhaul.

This commit marks the move towards treating the fibril library as a mere
implementation of a generic threading interface. Understood as a layer that
wraps the kernel threads, we not only have to wrap threading itself, but also
every syscall that blocks the kernel thread (by blocking, we mean thread not
doing useful work until an external event happens — e.g. locking a kernel
mutex or thread sleep is understood as blocking, but an as_area_create() is not,
despite potentially taking a long time to complete).

Consequently, we implement fibril_ipc_wait() as a fibril-native wrapper for
kernel's ipc_wait(), and also implement timer functionality like timeouts
as part of the fibril library. This removes the interdependency between fibril
implementation and the async framework — in theory, the fibril API could be
reimplemented as a simple 1:1 shim, and the async framework would continue
working normally (note that the current implementation of loader complicates
this).

To better isolate the fibril internals from the implementation of high-level
synchronization, a fibril_event_t is added. This object conceptually acts
like a single slot wait queue. All other synchronization is implemented in
terms of this primitive.

  • Property mode set to 100644
File size: 4.9 KB
Line 
1/*
2 * Copyright (c) 2006 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libc
30 * @{
31 */
32/** @file
33 */
34
35#include <libc.h>
36#include <stdbool.h>
37#include <stdlib.h>
38#include <libarch/faddr.h>
39#include <abi/proc/uarg.h>
40#include <fibril.h>
41#include <stack.h>
42#include <str.h>
43#include <async.h>
44#include <errno.h>
45#include <as.h>
46#include "private/thread.h"
47#include "private/fibril.h"
48
49/** Main thread function.
50 *
51 * This function is called from __thread_entry() and is used
52 * to call the thread's implementing function and perform cleanup
53 * and exit when thread returns back.
54 *
55 * @param uarg Pointer to userspace argument structure.
56 *
57 */
58void __thread_main(uspace_arg_t *uarg)
59{
60 assert(!__tcb_is_set());
61
62 fibril_t *fibril = uarg->uspace_thread_arg;
63 assert(fibril);
64
65 __tcb_set(fibril->tcb);
66
67 uarg->uspace_thread_function(fibril->arg);
68 /*
69 * XXX: we cannot free the userspace stack while running on it
70 *
71 * free(uarg->uspace_stack);
72 * free(uarg);
73 */
74
75 fibril_teardown(fibril);
76 thread_exit(0);
77}
78
79/** Create userspace thread.
80 *
81 * This function creates new userspace thread and allocates userspace
82 * stack and userspace argument structure for it.
83 *
84 * @param function Function implementing the thread.
85 * @param arg Argument to be passed to thread.
86 * @param name Symbolic name of the thread.
87 * @param tid Thread ID of the newly created thread.
88 *
89 * @return Zero on success or a code from @ref errno.h on failure.
90 */
91errno_t thread_create(void (*function)(void *), void *arg, const char *name,
92 thread_id_t *tid)
93{
94 uspace_arg_t *uarg = calloc(1, sizeof(uspace_arg_t));
95 if (!uarg)
96 return ENOMEM;
97
98 fibril_t *fibril = fibril_alloc();
99 if (!fibril) {
100 free(uarg);
101 return ENOMEM;
102 }
103
104 size_t stack_size = stack_size_get();
105 void *stack = as_area_create(AS_AREA_ANY, stack_size,
106 AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE | AS_AREA_GUARD |
107 AS_AREA_LATE_RESERVE, AS_AREA_UNPAGED);
108 if (stack == AS_MAP_FAILED) {
109 fibril_teardown(fibril);
110 free(uarg);
111 return ENOMEM;
112 }
113
114 fibril->arg = arg;
115 uarg->uspace_entry = (void *) FADDR(__thread_entry);
116 uarg->uspace_stack = stack;
117 uarg->uspace_stack_size = stack_size;
118 uarg->uspace_thread_function = function;
119 uarg->uspace_thread_arg = fibril;
120 uarg->uspace_uarg = uarg;
121
122 errno_t rc = (errno_t) __SYSCALL4(SYS_THREAD_CREATE, (sysarg_t) uarg,
123 (sysarg_t) name, (sysarg_t) str_size(name), (sysarg_t) tid);
124
125 if (rc != EOK) {
126 /*
127 * Failed to create a new thread.
128 * Free up the allocated data.
129 */
130 as_area_destroy(stack);
131 free(uarg);
132 }
133
134 return rc;
135}
136
137/** Terminate current thread.
138 *
139 * @param status Exit status. Currently not used.
140 *
141 */
142void thread_exit(int status)
143{
144 __SYSCALL1(SYS_THREAD_EXIT, (sysarg_t) status);
145
146 /* Unreachable */
147 while (true)
148 ;
149}
150
151/** Detach thread.
152 *
153 * Currently not implemented.
154 *
155 * @param thread TID.
156 */
157void thread_detach(thread_id_t thread)
158{
159}
160
161/** Get current thread ID.
162 *
163 * @return Current thread ID.
164 */
165thread_id_t thread_get_id(void)
166{
167 thread_id_t thread_id;
168
169 (void) __SYSCALL1(SYS_THREAD_GET_ID, (sysarg_t) &thread_id);
170
171 return thread_id;
172}
173
174/** Wait unconditionally for specified number of microseconds
175 *
176 */
177int thread_usleep(useconds_t usec)
178{
179 (void) __SYSCALL1(SYS_THREAD_USLEEP, usec);
180 return 0;
181}
182
183/** Wait unconditionally for specified number of seconds
184 *
185 */
186unsigned int thread_sleep(unsigned int sec)
187{
188 /*
189 * Sleep in 1000 second steps to support
190 * full argument range
191 */
192
193 while (sec > 0) {
194 unsigned int period = (sec > 1000) ? 1000 : sec;
195
196 thread_usleep(period * 1000000);
197 sec -= period;
198 }
199
200 return 0;
201}
202
203/** @}
204 */
Note: See TracBrowser for help on using the repository browser.