source: mainline/uspace/lib/c/generic/fibril.c@ a53ed3a

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

Use errno_t in all uspace and kernel code.

Change type of every variable, parameter and return value that holds an
<errno.h> constant to either errno_t (the usual case), or sys_errno_t
(some places in kernel). This is for the purpose of self-documentation,
as well as for type-checking with a bit of type definition hackery.

Although this is a massive commit, it is a simple text replacement, and thus
is very easy to verify. Simply do the following:

`
git checkout <this commit's hash>
git reset HEAD
git add .
tools/srepl '\berrno_t\b' int
git add .
tools/srepl '\bsys_errno_t\b' sysarg_t
git reset
git diff
`

While this doesn't ensure that the replacements are correct, it does ensure
that the commit doesn't do anything except those replacements. Since errno_t
is typedef'd to int in the usual case (and sys_errno_t to sysarg_t), even if
incorrect, this commit cannot change behavior.

  • Property mode set to 100644
File size: 8.7 KB
RevLine 
[bc1f1c2]1/*
2 * Copyright (c) 2006 Ondrej Palkovsky
3 * Copyright (c) 2007 Jakub Jermar
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup libc
31 * @{
32 */
33/** @file
34 */
35
[d9c8c81]36#include <adt/list.h>
[bc1f1c2]37#include <fibril.h>
[fa23560]38#include <thread.h>
[0aae87a6]39#include <stack.h>
[fa23560]40#include <tls.h>
[38d150e]41#include <stdlib.h>
[1107050]42#include <abi/mm/as.h>
43#include <as.h>
[bc1f1c2]44#include <stdio.h>
[c0699467]45#include <libarch/barrier.h>
[bc1f1c2]46#include <libarch/faddr.h>
47#include <futex.h>
48#include <assert.h>
49#include <async.h>
50
[6c1bb0d]51#ifdef FUTEX_UPGRADABLE
[d54b303]52#include <rcu.h>
53#endif
[bc1f1c2]54
[cc27c8c5]55/**
[596d65c]56 * This futex serializes access to ready_list,
[2654afb]57 * manager_list and fibril_list.
[596d65c]58 */
[927a181e]59static futex_t fibril_futex = FUTEX_INITIALIZER;
[12f91130]60
[bc1f1c2]61static LIST_INITIALIZE(ready_list);
62static LIST_INITIALIZE(manager_list);
[c1b979a]63static LIST_INITIALIZE(fibril_list);
[bc1f1c2]64
[596d65c]65/** Function that spans the whole life-cycle of a fibril.
66 *
67 * Each fibril begins execution in this function. Then the function implementing
68 * the fibril logic is called. After its return, the return value is saved.
69 * The fibril then switches to another fibril, which cleans up after it.
70 *
71 */
72static void fibril_main(void)
[bc1f1c2]73{
[596d65c]74 fibril_t *fibril = __tcb_get()->fibril_data;
[d54b303]75
[6c1bb0d]76#ifdef FUTEX_UPGRADABLE
[d54b303]77 rcu_register_fibril();
78#endif
[596d65c]79
80 /* Call the implementing function. */
81 fibril->retval = fibril->func(fibril->arg);
82
[c721d26]83 futex_down(&async_futex);
[596d65c]84 fibril_switch(FIBRIL_FROM_DEAD);
85 /* Not reached */
86}
[bc1f1c2]87
[596d65c]88/** Setup fibril information into TCB structure
89 *
90 */
91fibril_t *fibril_setup(void)
92{
[31399f3]93 tcb_t *tcb = tls_make();
[bc1f1c2]94 if (!tcb)
95 return NULL;
[596d65c]96
97 fibril_t *fibril = malloc(sizeof(fibril_t));
98 if (!fibril) {
[31399f3]99 tls_free(tcb);
[bc1f1c2]100 return NULL;
101 }
[596d65c]102
103 tcb->fibril_data = fibril;
104 fibril->tcb = tcb;
105
106 fibril->func = NULL;
107 fibril->arg = NULL;
108 fibril->stack = NULL;
109 fibril->clean_after_me = NULL;
110 fibril->retval = 0;
111 fibril->flags = 0;
112
[8cf6709]113 fibril->waits_for = NULL;
[4d11204]114
[c170438]115 fibril->switches = 0;
116
[6d87dce]117 /*
118 * We are called before __tcb_set(), so we need to use
119 * futex_down/up() instead of futex_lock/unlock() that
120 * may attempt to access TLS.
121 */
122 futex_down(&fibril_futex);
[c1b979a]123 list_append(&fibril->all_link, &fibril_list);
[6d87dce]124 futex_up(&fibril_futex);
[8cf6709]125
[596d65c]126 return fibril;
[bc1f1c2]127}
128
[4d11204]129void fibril_teardown(fibril_t *fibril, bool locked)
130{
131 if (!locked)
132 futex_lock(&fibril_futex);
[c1b979a]133 list_remove(&fibril->all_link);
[4d11204]134 if (!locked)
135 futex_unlock(&fibril_futex);
[31399f3]136 tls_free(fibril->tcb);
[596d65c]137 free(fibril);
[bc1f1c2]138}
139
[116d3f6f]140/** Switch from the current fibril.
[bc1f1c2]141 *
[c721d26]142 * If stype is FIBRIL_TO_MANAGER or FIBRIL_FROM_DEAD, the async_futex must
143 * be held.
[bc1f1c2]144 *
[596d65c]145 * @param stype Switch type. One of FIBRIL_PREEMPT, FIBRIL_TO_MANAGER,
146 * FIBRIL_FROM_MANAGER, FIBRIL_FROM_DEAD. The parameter
147 * describes the circumstances of the switch.
148 *
149 * @return 0 if there is no ready fibril,
150 * @return 1 otherwise.
151 *
[bc1f1c2]152 */
[116d3f6f]153int fibril_switch(fibril_switch_type_t stype)
[bc1f1c2]154{
[df7cbc6]155 futex_lock(&fibril_futex);
[c721d26]156
[2654afb]157 switch (stype) {
158 case FIBRIL_PREEMPT:
159 case FIBRIL_FROM_MANAGER:
160 if (list_empty(&ready_list)) {
161 futex_unlock(&fibril_futex);
162 return 0;
[bc1f1c2]163 }
[2654afb]164 break;
165 case FIBRIL_TO_MANAGER:
166 case FIBRIL_FROM_DEAD:
[c721d26]167 /* Make sure the async_futex is held. */
168 assert((atomic_signed_t) async_futex.val.count <= 0);
169
[2654afb]170 /* If we are going to manager and none exists, create it */
[bc1f1c2]171 while (list_empty(&manager_list)) {
[df7cbc6]172 futex_unlock(&fibril_futex);
[bc1f1c2]173 async_create_manager();
[df7cbc6]174 futex_lock(&fibril_futex);
[bc1f1c2]175 }
[2654afb]176 break;
[bc1f1c2]177 }
178
[36e9cd1]179 fibril_t *srcf = __tcb_get()->fibril_data;
[bc1f1c2]180 if (stype != FIBRIL_FROM_DEAD) {
[36e9cd1]181
[bc1f1c2]182 /* Save current state */
183 if (!context_save(&srcf->ctx)) {
184 if (srcf->clean_after_me) {
185 /*
186 * Cleanup after the dead fibril from which we
187 * restored context here.
188 */
[36e9cd1]189 void *stack = srcf->clean_after_me->stack;
[116d3f6f]190 if (stack) {
191 /*
192 * This check is necessary because a
193 * thread could have exited like a
194 * normal fibril using the
195 * FIBRIL_FROM_DEAD switch type. In that
196 * case, its fibril will not have the
197 * stack member filled.
198 */
[1107050]199 as_area_destroy(stack);
[116d3f6f]200 }
[4d11204]201 fibril_teardown(srcf->clean_after_me, true);
[bc1f1c2]202 srcf->clean_after_me = NULL;
203 }
[36e9cd1]204
[df7cbc6]205 return 1; /* futex_unlock already done here */
[bc1f1c2]206 }
[36e9cd1]207
[2654afb]208 /* Put the current fibril into the correct run list */
209 switch (stype) {
210 case FIBRIL_PREEMPT:
[bc1f1c2]211 list_append(&srcf->link, &ready_list);
[2654afb]212 break;
213 case FIBRIL_FROM_MANAGER:
[bc1f1c2]214 list_append(&srcf->link, &manager_list);
[2654afb]215 break;
216 default:
217 assert(stype == FIBRIL_TO_MANAGER);
218
[c170438]219 srcf->switches++;
220
[bc1f1c2]221 /*
[2654afb]222 * Don't put the current fibril into any list, it should
223 * already be somewhere, or it will be lost.
[bc1f1c2]224 */
[2654afb]225 break;
[bc1f1c2]226 }
227 }
[116d3f6f]228
[36e9cd1]229 fibril_t *dstf;
[2654afb]230
231 /* Choose a new fibril to run */
232 switch (stype) {
233 case FIBRIL_TO_MANAGER:
234 case FIBRIL_FROM_DEAD:
[b72efe8]235 dstf = list_get_instance(list_first(&manager_list), fibril_t,
236 link);
[36e9cd1]237
[116d3f6f]238 if (stype == FIBRIL_FROM_DEAD)
[bc1f1c2]239 dstf->clean_after_me = srcf;
[2654afb]240 break;
241 default:
242 dstf = list_get_instance(list_first(&ready_list), fibril_t,
243 link);
244 break;
[bc1f1c2]245 }
[2654afb]246
[bc1f1c2]247 list_remove(&dstf->link);
[36e9cd1]248
[df7cbc6]249 futex_unlock(&fibril_futex);
[d54b303]250
[6c1bb0d]251#ifdef FUTEX_UPGRADABLE
[d54b303]252 if (stype == FIBRIL_FROM_DEAD) {
253 rcu_deregister_fibril();
254 }
255#endif
256
[bc1f1c2]257 context_restore(&dstf->ctx);
258 /* not reached */
259}
260
261/** Create a new fibril.
262 *
[596d65c]263 * @param func Implementing function of the new fibril.
264 * @param arg Argument to pass to func.
[eceff5f]265 * @param stksz Stack size in bytes.
[596d65c]266 *
267 * @return 0 on failure or TLS of the new fibril.
[bc1f1c2]268 *
269 */
[b7fd2a0]270fid_t fibril_create_generic(errno_t (*func)(void *), void *arg, size_t stksz)
[bc1f1c2]271{
[596d65c]272 fibril_t *fibril;
273
274 fibril = fibril_setup();
275 if (fibril == NULL)
[bc1f1c2]276 return 0;
[596d65c]277
[eceff5f]278 size_t stack_size = (stksz == FIBRIL_DFLT_STK_SIZE) ?
279 stack_size_get() : stksz;
[6aeca0d]280 fibril->stack = as_area_create(AS_AREA_ANY, stack_size,
[1107050]281 AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE | AS_AREA_GUARD |
[6aeca0d]282 AS_AREA_LATE_RESERVE, AS_AREA_UNPAGED);
[1107050]283 if (fibril->stack == (void *) -1) {
[4d11204]284 fibril_teardown(fibril, false);
[bc1f1c2]285 return 0;
286 }
[116d3f6f]287
[596d65c]288 fibril->func = func;
289 fibril->arg = arg;
[7f122e3]290
[596d65c]291 context_save(&fibril->ctx);
292 context_set(&fibril->ctx, FADDR(fibril_main), fibril->stack,
[0aae87a6]293 stack_size, fibril->tcb);
[bc1f1c2]294
[596d65c]295 return (fid_t) fibril;
[bc1f1c2]296}
297
[32d19f7]298/** Delete a fibril that has never run.
299 *
300 * Free resources of a fibril that has been created with fibril_create()
301 * but never readied using fibril_add_ready().
302 *
303 * @param fid Pointer to the fibril structure of the fibril to be
304 * added.
305 */
306void fibril_destroy(fid_t fid)
307{
308 fibril_t *fibril = (fibril_t *) fid;
309
[1107050]310 as_area_destroy(fibril->stack);
[4d11204]311 fibril_teardown(fibril, false);
[32d19f7]312}
313
[bc1f1c2]314/** Add a fibril to the ready list.
315 *
[596d65c]316 * @param fid Pointer to the fibril structure of the fibril to be
317 * added.
318 *
[bc1f1c2]319 */
320void fibril_add_ready(fid_t fid)
321{
[596d65c]322 fibril_t *fibril = (fibril_t *) fid;
323
[df7cbc6]324 futex_lock(&fibril_futex);
[2654afb]325 list_append(&fibril->link, &ready_list);
[df7cbc6]326 futex_unlock(&fibril_futex);
[bc1f1c2]327}
328
329/** Add a fibril to the manager list.
330 *
[596d65c]331 * @param fid Pointer to the fibril structure of the fibril to be
332 * added.
333 *
[bc1f1c2]334 */
335void fibril_add_manager(fid_t fid)
336{
[596d65c]337 fibril_t *fibril = (fibril_t *) fid;
338
[df7cbc6]339 futex_lock(&fibril_futex);
[596d65c]340 list_append(&fibril->link, &manager_list);
[df7cbc6]341 futex_unlock(&fibril_futex);
[bc1f1c2]342}
343
344/** Remove one manager from the manager list. */
345void fibril_remove_manager(void)
346{
[df7cbc6]347 futex_lock(&fibril_futex);
[596d65c]348 if (!list_empty(&manager_list))
[b72efe8]349 list_remove(list_first(&manager_list));
[df7cbc6]350 futex_unlock(&fibril_futex);
[bc1f1c2]351}
352
353/** Return fibril id of the currently running fibril.
354 *
[3562ec82]355 * @return fibril ID of the currently running fibril.
356 *
[bc1f1c2]357 */
358fid_t fibril_get_id(void)
359{
360 return (fid_t) __tcb_get()->fibril_data;
361}
362
363/** @}
364 */
Note: See TracBrowser for help on using the repository browser.