Changeset 8119363 in mainline


Ignore:
Timestamp:
2018-06-26T17:35:40Z (6 years ago)
Author:
Jiří Zárevúcky <jiri.zarevucky@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
6e569bf
Parents:
fbfe59d (diff), e768aea (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge some preliminary async/fibril framework changes.

Files:
1 added
30 edited

Legend:

Unmodified
Added
Removed
  • HelenOS.config

    rfbfe59d r8119363  
    385385! CONFIG_UBSAN_KERNEL (n/y)
    386386
     387% Track owner for futexes in userspace.
     388! CONFIG_DEBUG_FUTEX (y/n)
     389
    387390% Deadlock detection support for spinlocks
    388391! [CONFIG_DEBUG=y&CONFIG_SMP=y] CONFIG_DEBUG_SPINLOCK (y/n)
  • abi/include/abi/synch.h

    rfbfe59d r8119363  
    4545/** Interruptible operation. */
    4646#define SYNCH_FLAGS_INTERRUPTIBLE  (1 << 1)
     47/** Futex operation (makes sleep with timeout composable). */
     48#define SYNCH_FLAGS_FUTEX          (1 << 2)
    4749
    4850#endif
  • kernel/generic/include/proc/thread.h

    rfbfe59d r8119363  
    112112        /** If true, the thread can be interrupted from sleep. */
    113113        bool sleep_interruptible;
     114
     115        /**
     116         * If true, and this thread's sleep returns without a wakeup
     117         * (timed out or interrupted), waitq ignores the next wakeup.
     118         * This is necessary for futex to be able to handle those conditions.
     119         */
     120        bool sleep_composable;
     121
    114122        /** Wait queue in which this thread sleeps. */
    115123        waitq_t *sleep_queue;
  • kernel/generic/include/synch/futex.h

    rfbfe59d r8119363  
    5353
    5454extern void futex_init(void);
    55 extern sys_errno_t sys_futex_sleep(uintptr_t);
     55extern sys_errno_t sys_futex_sleep(uintptr_t, uintptr_t);
    5656extern sys_errno_t sys_futex_wakeup(uintptr_t);
    5757
  • kernel/generic/include/synch/waitq.h

    rfbfe59d r8119363  
    6262        int missed_wakeups;
    6363
     64        /** Number of wakeups that need to be ignored due to futex timeout. */
     65        int ignore_wakeups;
     66
    6467        /** List of sleeping threads for which there was no missed_wakeup. */
    6568        list_t sleepers;
  • kernel/generic/src/proc/thread.c

    rfbfe59d r8119363  
    383383        timeout_initialize(&thread->sleep_timeout);
    384384        thread->sleep_interruptible = false;
     385        thread->sleep_composable = false;
    385386        thread->sleep_queue = NULL;
    386387        thread->timeout_pending = false;
  • kernel/generic/src/synch/futex.c

    rfbfe59d r8119363  
    398398}
    399399
    400 /** Sleep in futex wait queue.
    401  *
    402  * @param uaddr         Userspace address of the futex counter.
     400/** Sleep in futex wait queue with a timeout.
     401 *  If the sleep times out or is interrupted, the next wakeup is ignored.
     402 *  The userspace portion of the call must handle this condition.
     403 *
     404 * @param uaddr         Userspace address of the futex counter.
     405 * @param timeout       Maximum number of useconds to sleep. 0 means no limit.
    403406 *
    404407 * @return              If there is no physical mapping for uaddr ENOENT is
     
    406409 *                      waitq_sleep_timeout().
    407410 */
    408 sys_errno_t sys_futex_sleep(uintptr_t uaddr)
     411sys_errno_t sys_futex_sleep(uintptr_t uaddr, uintptr_t timeout)
    409412{
    410413        futex_t *futex = get_futex(uaddr);
     
    417420#endif
    418421
    419         errno_t rc = waitq_sleep_timeout(
    420             &futex->wq, 0, SYNCH_FLAGS_INTERRUPTIBLE, NULL);
     422        errno_t rc = waitq_sleep_timeout(&futex->wq, timeout,
     423            SYNCH_FLAGS_INTERRUPTIBLE | SYNCH_FLAGS_FUTEX, NULL);
    421424
    422425#ifdef CONFIG_UDEBUG
  • kernel/generic/src/synch/waitq.c

    rfbfe59d r8119363  
    5757#include <adt/list.h>
    5858#include <arch/cycle.h>
     59#include <mem.h>
    5960
    6061static void waitq_sleep_timed_out(void *);
     
    7172void waitq_initialize(waitq_t *wq)
    7273{
     74        memsetb(wq, sizeof(*wq), 0);
    7375        irq_spinlock_initialize(&wq->lock, "wq.lock");
    7476        list_initialize(&wq->sleepers);
    75         wq->missed_wakeups = 0;
    7677}
    7778
     
    114115                thread->saved_context = thread->sleep_timeout_context;
    115116                do_wakeup = true;
     117                if (thread->sleep_composable)
     118                        wq->ignore_wakeups++;
    116119                thread->sleep_queue = NULL;
    117120                irq_spinlock_unlock(&wq->lock, false);
     
    176179                list_remove(&thread->wq_link);
    177180                thread->saved_context = thread->sleep_interruption_context;
     181                if (thread->sleep_composable)
     182                        wq->ignore_wakeups++;
    178183                do_wakeup = true;
    179184                thread->sleep_queue = NULL;
     
    393398         */
    394399        irq_spinlock_lock(&THREAD->lock, false);
     400
     401        THREAD->sleep_composable = (flags & SYNCH_FLAGS_FUTEX);
    395402
    396403        if (flags & SYNCH_FLAGS_INTERRUPTIBLE) {
     
    538545        assert(irq_spinlock_locked(&wq->lock));
    539546
     547        if (wq->ignore_wakeups > 0) {
     548                if (mode == WAKEUP_FIRST) {
     549                        wq->ignore_wakeups--;
     550                        return;
     551                }
     552                wq->ignore_wakeups = 0;
     553        }
     554
    540555loop:
    541556        if (list_empty(&wq->sleepers)) {
  • uspace/app/nic/nic.c

    rfbfe59d r8119363  
    3434 */
    3535
     36#include <assert.h>
    3637#include <errno.h>
    3738#include <loc.h>
  • uspace/app/taskdump/fibrildump.c

    rfbfe59d r8119363  
    3333 */
    3434
     35#include <adt/list.h>
     36#include <context.h>
    3537#include <errno.h>
    3638#include <fibril.h>
     
    4244#include <taskdump.h>
    4345#include <udebug.h>
     46
     47struct fibril {
     48        link_t all_link;
     49        context_t ctx;
     50        uint8_t __opaque[];
     51};
    4452
    4553static errno_t fibrildump_read_uintptr(void *, uintptr_t, uintptr_t *);
  • uspace/lib/c/generic/assert.c

    rfbfe59d r8119363  
    3838#include <stacktrace.h>
    3939#include <stdint.h>
     40#include <task.h>
    4041
    4142static atomic_t failed_asserts = { 0 };
     
    4647         * Send the message safely to kio. Nested asserts should not occur.
    4748         */
    48         kio_printf("Assertion failed (%s) in file \"%s\", line %u.\n",
    49             cond, file, line);
     49        kio_printf("Assertion failed (%s) in task %ld, file \"%s\", line %u.\n",
     50            cond, (long) task_get_id(), file, line);
     51
     52        stacktrace_kio_print();
    5053
    5154        /* Sometimes we know in advance that regular printf() would likely fail. */
     
    5861         * Send the message safely to kio. Nested asserts should not occur.
    5962         */
    60         kio_printf("Assertion failed (%s) in file \"%s\", line %u.\n",
    61             cond, file, line);
     63        kio_printf("Assertion failed (%s) in task %ld, file \"%s\", line %u.\n",
     64            cond, (long) task_get_id(), file, line);
     65
     66        stacktrace_kio_print();
    6267
    6368        /*
     
    7277         * assertions.
    7378         */
    74         printf("Assertion failed (%s) in file \"%s\", line %u.\n",
    75             cond, file, line);
     79        kio_printf("Assertion failed (%s) in task %ld, file \"%s\", line %u.\n",
     80            cond, (long) task_get_id(), file, line);
    7681        stacktrace_print();
    7782
  • uspace/lib/c/generic/async/client.c

    rfbfe59d r8119363  
    121121#include <abi/mm/as.h>
    122122#include "../private/libc.h"
     123#include "../private/fibril.h"
    123124
    124125/** Naming service session */
     
    241242        assert(arg);
    242243
    243         futex_down(&async_futex);
     244        futex_lock(&async_futex);
    244245
    245246        amsg_t *msg = (amsg_t *) arg;
     
    266267        }
    267268
    268         futex_up(&async_futex);
     269        futex_unlock(&async_futex);
    269270}
    270271
     
    355356        amsg_t *msg = (amsg_t *) amsgid;
    356357
    357         futex_down(&async_futex);
     358        futex_lock(&async_futex);
    358359
    359360        assert(!msg->forget);
     
    361362
    362363        if (msg->done) {
    363                 futex_up(&async_futex);
     364                futex_unlock(&async_futex);
    364365                goto done;
    365366        }
     
    370371
    371372        /* Leave the async_futex locked when entering this function */
    372         fibril_switch(FIBRIL_TO_MANAGER);
    373 
    374         /* Futex is up automatically after fibril_switch */
     373        fibril_switch(FIBRIL_FROM_BLOCKED);
     374        futex_unlock(&async_futex);
    375375
    376376done:
     
    401401        amsg_t *msg = (amsg_t *) amsgid;
    402402
    403         futex_down(&async_futex);
     403        futex_lock(&async_futex);
    404404
    405405        assert(!msg->forget);
     
    407407
    408408        if (msg->done) {
    409                 futex_up(&async_futex);
     409                futex_unlock(&async_futex);
    410410                goto done;
    411411        }
     
    443443
    444444        /* Leave the async_futex locked when entering this function */
    445         fibril_switch(FIBRIL_TO_MANAGER);
    446 
    447         /* Futex is up automatically after fibril_switch */
     445        fibril_switch(FIBRIL_FROM_BLOCKED);
     446        futex_unlock(&async_futex);
    448447
    449448        if (!msg->done)
     
    475474        assert(!msg->destroyed);
    476475
    477         futex_down(&async_futex);
     476        futex_lock(&async_futex);
    478477
    479478        if (msg->done) {
     
    484483        }
    485484
    486         futex_up(&async_futex);
     485        futex_unlock(&async_futex);
    487486}
    488487
     
    504503        tv_add_diff(&awaiter.to_event.expires, timeout);
    505504
    506         futex_down(&async_futex);
     505        futex_lock(&async_futex);
    507506
    508507        async_insert_timeout(&awaiter);
    509508
    510509        /* Leave the async_futex locked when entering this function */
    511         fibril_switch(FIBRIL_TO_MANAGER);
    512 
    513         /* Futex is up automatically after fibril_switch() */
     510        fibril_switch(FIBRIL_FROM_BLOCKED);
     511        futex_unlock(&async_futex);
    514512}
    515513
  • uspace/lib/c/generic/async/server.c

    rfbfe59d r8119363  
    120120#include <abi/mm/as.h>
    121121#include "../private/libc.h"
     122#include "../private/fibril.h"
    122123
    123124/** Async framework global futex */
     
    431432         * Remove myself from the connection hash table.
    432433         */
    433         futex_down(&async_futex);
     434        futex_lock(&async_futex);
    434435        hash_table_remove(&conn_hash_table, &(conn_key_t){
    435436                .task_id = fibril_connection->in_task_id,
    436437                .phone_hash = fibril_connection->in_phone_hash
    437438        });
    438         futex_up(&async_futex);
     439        futex_unlock(&async_futex);
    439440
    440441        /*
     
    519520        /* Add connection to the connection hash table */
    520521
    521         futex_down(&async_futex);
     522        futex_lock(&async_futex);
    522523        hash_table_insert(&conn_hash_table, &conn->link);
    523         futex_up(&async_futex);
     524        futex_unlock(&async_futex);
    524525
    525526        fibril_add_ready(conn->wdata.fid);
     
    647648        assert(call);
    648649
    649         futex_down(&async_futex);
     650        futex_lock(&async_futex);
    650651
    651652        ht_link_t *link = hash_table_find(&conn_hash_table, &(conn_key_t){
     
    654655        });
    655656        if (!link) {
    656                 futex_up(&async_futex);
     657                futex_unlock(&async_futex);
    657658                return false;
    658659        }
     
    662663        msg_t *msg = malloc(sizeof(*msg));
    663664        if (!msg) {
    664                 futex_up(&async_futex);
     665                futex_unlock(&async_futex);
    665666                return false;
    666667        }
     
    686687        }
    687688
    688         futex_up(&async_futex);
     689        futex_unlock(&async_futex);
    689690        return true;
    690691}
     
    961962        connection_t *conn = fibril_connection;
    962963
    963         futex_down(&async_futex);
     964        futex_lock(&async_futex);
    964965
    965966        if (usecs) {
     
    981982                        memset(call, 0, sizeof(ipc_call_t));
    982983                        IPC_SET_IMETHOD(*call, IPC_M_PHONE_HUNGUP);
    983                         futex_up(&async_futex);
     984                        futex_unlock(&async_futex);
    984985                        return conn->close_chandle;
    985986                }
     
    996997                 * case, route_call() will perform the wakeup.
    997998                 */
    998                 fibril_switch(FIBRIL_TO_MANAGER);
    999 
    1000                 /*
    1001                  * Futex is up after getting back from async_manager.
    1002                  * Get it again.
    1003                  */
    1004                 futex_down(&async_futex);
     999                fibril_switch(FIBRIL_FROM_BLOCKED);
     1000
    10051001                if ((usecs) && (conn->wdata.to_event.occurred) &&
    10061002                    (list_empty(&conn->msg_queue))) {
    10071003                        /* If we timed out -> exit */
    1008                         futex_up(&async_futex);
     1004                        futex_unlock(&async_futex);
    10091005                        return CAP_NIL;
    10101006                }
     
    10191015        free(msg);
    10201016
    1021         futex_up(&async_futex);
     1017        futex_unlock(&async_futex);
    10221018        return chandle;
    10231019}
     
    10701066        assert(call);
    10711067
    1072         /* Kernel notification */
    1073         if ((chandle == CAP_NIL) && (call->flags & IPC_CALL_NOTIF)) {
    1074                 queue_notification(call);
     1068        if (call->flags & IPC_CALL_ANSWERED)
     1069                return;
     1070
     1071        if (chandle == CAP_NIL) {
     1072                if (call->flags & IPC_CALL_NOTIF) {
     1073                        /* Kernel notification */
     1074                        queue_notification(call);
     1075                }
    10751076                return;
    10761077        }
     
    11001101
    11011102/** Fire all timeouts that expired. */
    1102 static void handle_expired_timeouts(void)
    1103 {
     1103static suseconds_t handle_expired_timeouts(unsigned int *flags)
     1104{
     1105        /* Make sure the async_futex is held. */
     1106        futex_assert_is_locked(&async_futex);
     1107
    11041108        struct timeval tv;
    11051109        getuptime(&tv);
    11061110
    1107         futex_down(&async_futex);
     1111        bool fired = false;
    11081112
    11091113        link_t *cur = list_first(&timeout_list);
     
    11121116                    list_get_instance(cur, awaiter_t, to_event.link);
    11131117
    1114                 if (tv_gt(&waiter->to_event.expires, &tv))
    1115                         break;
     1118                if (tv_gt(&waiter->to_event.expires, &tv)) {
     1119                        if (fired) {
     1120                                *flags = SYNCH_FLAGS_NON_BLOCKING;
     1121                                return 0;
     1122                        }
     1123                        *flags = 0;
     1124                        return tv_sub_diff(&waiter->to_event.expires, &tv);
     1125                }
    11161126
    11171127                list_remove(&waiter->to_event.link);
     
    11261136                        waiter->active = true;
    11271137                        fibril_add_ready(waiter->fid);
     1138                        fired = true;
    11281139                }
    11291140
     
    11311142        }
    11321143
    1133         futex_up(&async_futex);
     1144        if (fired) {
     1145                *flags = SYNCH_FLAGS_NON_BLOCKING;
     1146                return 0;
     1147        }
     1148
     1149        return SYNCH_NO_TIMEOUT;
    11341150}
    11351151
     
    11421158{
    11431159        while (true) {
    1144                 if (fibril_switch(FIBRIL_FROM_MANAGER)) {
    1145                         futex_up(&async_futex);
    1146                         /*
    1147                          * async_futex is always held when entering a manager
    1148                          * fibril.
    1149                          */
    1150                         continue;
    1151                 }
    1152 
    1153                 futex_down(&async_futex);
    1154 
    1155                 suseconds_t timeout;
     1160                futex_lock(&async_futex);
     1161                fibril_switch(FIBRIL_FROM_MANAGER);
     1162
     1163                /*
     1164                 * The switch only returns when there is no non-manager fibril
     1165                 * it can run.
     1166                 */
     1167
    11561168                unsigned int flags = SYNCH_FLAGS_NONE;
    1157                 if (!list_empty(&timeout_list)) {
    1158                         awaiter_t *waiter = list_get_instance(
    1159                             list_first(&timeout_list), awaiter_t, to_event.link);
    1160 
    1161                         struct timeval tv;
    1162                         getuptime(&tv);
    1163 
    1164                         if (tv_gteq(&tv, &waiter->to_event.expires)) {
    1165                                 futex_up(&async_futex);
    1166                                 handle_expired_timeouts();
    1167                                 /*
    1168                                  * Notice that even if the event(s) already
    1169                                  * expired (and thus the other fibril was
    1170                                  * supposed to be running already),
    1171                                  * we check for incoming IPC.
    1172                                  *
    1173                                  * Otherwise, a fibril that continuously
    1174                                  * creates (almost) expired events could
    1175                                  * prevent IPC retrieval from the kernel.
    1176                                  */
    1177                                 timeout = 0;
    1178                                 flags = SYNCH_FLAGS_NON_BLOCKING;
    1179 
    1180                         } else {
    1181                                 timeout = tv_sub_diff(&waiter->to_event.expires,
    1182                                     &tv);
    1183                                 futex_up(&async_futex);
    1184                         }
    1185                 } else {
    1186                         futex_up(&async_futex);
    1187                         timeout = SYNCH_NO_TIMEOUT;
    1188                 }
     1169                suseconds_t next_timeout = handle_expired_timeouts(&flags);
     1170                futex_unlock(&async_futex);
    11891171
    11901172                atomic_inc(&threads_in_ipc_wait);
    11911173
    11921174                ipc_call_t call;
    1193                 errno_t rc = ipc_wait_cycle(&call, timeout, flags);
     1175                errno_t rc = ipc_wait_cycle(&call, next_timeout, flags);
    11941176
    11951177                atomic_dec(&threads_in_ipc_wait);
    11961178
    11971179                assert(rc == EOK);
    1198 
    1199                 if (call.cap_handle == CAP_NIL) {
    1200                         if ((call.flags &
    1201                             (IPC_CALL_NOTIF | IPC_CALL_ANSWERED)) == 0) {
    1202                                 /* Neither a notification nor an answer. */
    1203                                 handle_expired_timeouts();
    1204                                 continue;
    1205                         }
    1206                 }
    1207 
    1208                 if (call.flags & IPC_CALL_ANSWERED)
    1209                         continue;
    1210 
    12111180                handle_call(call.cap_handle, &call);
    12121181        }
     
    12251194static errno_t async_manager_fibril(void *arg)
    12261195{
    1227         futex_up(&async_futex);
    1228 
    1229         /*
    1230          * async_futex is always locked when entering manager
    1231          */
    12321196        async_manager_worker();
    1233 
    12341197        return 0;
    12351198}
     
    18841847}
    18851848
     1849_Noreturn void async_manager(void)
     1850{
     1851        futex_lock(&async_futex);
     1852        fibril_switch(FIBRIL_FROM_DEAD);
     1853        __builtin_unreachable();
     1854}
     1855
    18861856/** @}
    18871857 */
  • uspace/lib/c/generic/fibril.c

    rfbfe59d r8119363  
    4949#include <async.h>
    5050
    51 #ifdef FUTEX_UPGRADABLE
    52 #include <rcu.h>
    53 #endif
     51#include "private/fibril.h"
     52
    5453
    5554/**
     
    7271static void fibril_main(void)
    7372{
    74         /* fibril_futex is locked when a fibril is first started. */
    75         futex_unlock(&fibril_futex);
    76 
    77         fibril_t *fibril = __tcb_get()->fibril_data;
    78 
    79 #ifdef FUTEX_UPGRADABLE
    80         rcu_register_fibril();
    81 #endif
     73        /* fibril_futex and async_futex are locked when a fibril is started. */
     74        futex_unlock(&fibril_futex);
     75        futex_unlock(&async_futex);
     76
     77        fibril_t *fibril = fibril_self();
    8278
    8379        /* Call the implementing function. */
    8480        fibril->retval = fibril->func(fibril->arg);
    8581
    86         futex_down(&async_futex);
     82        futex_lock(&async_futex);
    8783        fibril_switch(FIBRIL_FROM_DEAD);
    8884        /* Not reached */
     
    9894                return NULL;
    9995
    100         fibril_t *fibril = malloc(sizeof(fibril_t));
     96        fibril_t *fibril = calloc(1, sizeof(fibril_t));
    10197        if (!fibril) {
    10298                tls_free(tcb);
     
    106102        tcb->fibril_data = fibril;
    107103        fibril->tcb = tcb;
    108 
    109         fibril->func = NULL;
    110         fibril->arg = NULL;
    111         fibril->stack = NULL;
    112         fibril->clean_after_me = NULL;
    113         fibril->retval = 0;
    114         fibril->flags = 0;
    115 
    116         fibril->waits_for = NULL;
    117104
    118105        /*
     
    141128/** Switch from the current fibril.
    142129 *
    143  * If stype is FIBRIL_TO_MANAGER or FIBRIL_FROM_DEAD, the async_futex must
    144  * be held.
     130 * The async_futex must be held when entering this function,
     131 * and is still held on return.
    145132 *
    146133 * @param stype Switch type. One of FIBRIL_PREEMPT, FIBRIL_TO_MANAGER,
     
    154141int fibril_switch(fibril_switch_type_t stype)
    155142{
     143        /* Make sure the async_futex is held. */
     144        futex_assert_is_locked(&async_futex);
     145
    156146        futex_lock(&fibril_futex);
    157147
    158         fibril_t *srcf = __tcb_get()->fibril_data;
     148        fibril_t *srcf = fibril_self();
    159149        fibril_t *dstf = NULL;
    160150
    161151        /* Choose a new fibril to run */
    162         switch (stype) {
    163         case FIBRIL_TO_MANAGER:
    164         case FIBRIL_FROM_DEAD:
    165                 /* Make sure the async_futex is held. */
    166                 assert((atomic_signed_t) async_futex.val.count <= 0);
     152        if (list_empty(&ready_list)) {
     153                if (stype == FIBRIL_PREEMPT || stype == FIBRIL_FROM_MANAGER) {
     154                        // FIXME: This means that as long as there is a fibril
     155                        // that only yields, IPC messages are never retrieved.
     156                        futex_unlock(&fibril_futex);
     157                        return 0;
     158                }
    167159
    168160                /* If we are going to manager and none exists, create it */
     
    175167                dstf = list_get_instance(list_first(&manager_list),
    176168                    fibril_t, link);
    177 
    178                 if (stype == FIBRIL_FROM_DEAD)
    179                         dstf->clean_after_me = srcf;
    180                 break;
    181         case FIBRIL_PREEMPT:
    182         case FIBRIL_FROM_MANAGER:
    183                 if (list_empty(&ready_list)) {
    184                         futex_unlock(&fibril_futex);
    185                         return 0;
    186                 }
    187 
     169        } else {
    188170                dstf = list_get_instance(list_first(&ready_list), fibril_t,
    189171                    link);
    190                 break;
    191         }
     172        }
     173
    192174        list_remove(&dstf->link);
     175        if (stype == FIBRIL_FROM_DEAD)
     176                dstf->clean_after_me = srcf;
    193177
    194178        /* Put the current fibril into the correct run list */
     
    201185                break;
    202186        case FIBRIL_FROM_DEAD:
     187        case FIBRIL_FROM_BLOCKED:
    203188                // Nothing.
    204189                break;
    205         case FIBRIL_TO_MANAGER:
    206                 /*
    207                  * Don't put the current fibril into any list, it should
    208                  * already be somewhere, or it will be lost.
    209                  */
    210                 break;
    211         }
    212 
    213 #ifdef FUTEX_UPGRADABLE
    214         if (stype == FIBRIL_FROM_DEAD) {
    215                 rcu_deregister_fibril();
    216         }
    217 #endif
     190        }
     191
     192        /* Bookkeeping. */
     193        futex_give_to(&fibril_futex, dstf);
     194        futex_give_to(&async_futex, dstf);
    218195
    219196        /* Swap to the next fibril. */
     
    345322}
    346323
     324fibril_t *fibril_self(void)
     325{
     326        return __tcb_get()->fibril_data;
     327}
     328
    347329/** Return fibril id of the currently running fibril.
    348330 *
     
    352334fid_t fibril_get_id(void)
    353335{
    354         return (fid_t) __tcb_get()->fibril_data;
     336        return (fid_t) fibril_self();
     337}
     338
     339void fibril_yield(void)
     340{
     341        futex_lock(&async_futex);
     342        (void) fibril_switch(FIBRIL_PREEMPT);
     343        futex_unlock(&async_futex);
    355344}
    356345
  • uspace/lib/c/generic/fibril_synch.c

    rfbfe59d r8119363  
    4545#include <stdio.h>
    4646#include "private/async.h"
     47#include "private/fibril.h"
    4748
    4849static void optimize_execution_power(void)
     
    105106        fibril_t *f = (fibril_t *) fibril_get_id();
    106107
    107         futex_down(&async_futex);
     108        futex_lock(&async_futex);
    108109        if (fm->counter-- <= 0) {
    109110                awaiter_t wdata;
     
    115116                check_for_deadlock(&fm->oi);
    116117                f->waits_for = &fm->oi;
    117                 fibril_switch(FIBRIL_TO_MANAGER);
     118                fibril_switch(FIBRIL_FROM_BLOCKED);
    118119        } else {
    119120                fm->oi.owned_by = f;
    120                 futex_up(&async_futex);
    121         }
     121        }
     122        futex_unlock(&async_futex);
    122123}
    123124
     
    126127        bool locked = false;
    127128
    128         futex_down(&async_futex);
     129        futex_lock(&async_futex);
    129130        if (fm->counter > 0) {
    130131                fm->counter--;
     
    132133                locked = true;
    133134        }
    134         futex_up(&async_futex);
     135        futex_unlock(&async_futex);
    135136
    136137        return locked;
     
    165166{
    166167        assert(fibril_mutex_is_locked(fm));
    167         futex_down(&async_futex);
     168        futex_lock(&async_futex);
    168169        _fibril_mutex_unlock_unsafe(fm);
    169         futex_up(&async_futex);
     170        futex_unlock(&async_futex);
    170171}
    171172
     
    174175        bool locked = false;
    175176
    176         futex_down(&async_futex);
     177        futex_lock(&async_futex);
    177178        if (fm->counter <= 0)
    178179                locked = true;
    179         futex_up(&async_futex);
     180        futex_unlock(&async_futex);
    180181
    181182        return locked;
     
    194195        fibril_t *f = (fibril_t *) fibril_get_id();
    195196
    196         futex_down(&async_futex);
     197        futex_lock(&async_futex);
    197198        if (frw->writers) {
    198199                awaiter_t wdata;
     
    201202                wdata.fid = (fid_t) f;
    202203                wdata.wu_event.inlist = true;
    203                 f->flags &= ~FIBRIL_WRITER;
     204                f->is_writer = false;
    204205                list_append(&wdata.wu_event.link, &frw->waiters);
    205206                check_for_deadlock(&frw->oi);
    206207                f->waits_for = &frw->oi;
    207                 fibril_switch(FIBRIL_TO_MANAGER);
     208                fibril_switch(FIBRIL_FROM_BLOCKED);
    208209        } else {
    209210                /* Consider the first reader the owner. */
    210211                if (frw->readers++ == 0)
    211212                        frw->oi.owned_by = f;
    212                 futex_up(&async_futex);
    213         }
     213        }
     214        futex_unlock(&async_futex);
    214215}
    215216
     
    218219        fibril_t *f = (fibril_t *) fibril_get_id();
    219220
    220         futex_down(&async_futex);
     221        futex_lock(&async_futex);
    221222        if (frw->writers || frw->readers) {
    222223                awaiter_t wdata;
     
    225226                wdata.fid = (fid_t) f;
    226227                wdata.wu_event.inlist = true;
    227                 f->flags |= FIBRIL_WRITER;
     228                f->is_writer = true;
    228229                list_append(&wdata.wu_event.link, &frw->waiters);
    229230                check_for_deadlock(&frw->oi);
    230231                f->waits_for = &frw->oi;
    231                 fibril_switch(FIBRIL_TO_MANAGER);
     232                fibril_switch(FIBRIL_FROM_BLOCKED);
    232233        } else {
    233234                frw->oi.owned_by = f;
    234235                frw->writers++;
    235                 futex_up(&async_futex);
    236         }
     236        }
     237        futex_unlock(&async_futex);
    237238}
    238239
    239240static void _fibril_rwlock_common_unlock(fibril_rwlock_t *frw)
    240241{
    241         futex_down(&async_futex);
     242        futex_lock(&async_futex);
    242243        if (frw->readers) {
    243244                if (--frw->readers) {
     
    276277                f->waits_for = NULL;
    277278
    278                 if (f->flags & FIBRIL_WRITER) {
     279                if (f->is_writer) {
    279280                        if (frw->readers)
    280281                                break;
     
    300301        }
    301302out:
    302         futex_up(&async_futex);
     303        futex_unlock(&async_futex);
    303304}
    304305
     
    319320        bool locked = false;
    320321
    321         futex_down(&async_futex);
     322        futex_lock(&async_futex);
    322323        if (frw->readers)
    323324                locked = true;
    324         futex_up(&async_futex);
     325        futex_unlock(&async_futex);
    325326
    326327        return locked;
     
    331332        bool locked = false;
    332333
    333         futex_down(&async_futex);
     334        futex_lock(&async_futex);
    334335        if (frw->writers) {
    335336                assert(frw->writers == 1);
    336337                locked = true;
    337338        }
    338         futex_up(&async_futex);
     339        futex_unlock(&async_futex);
    339340
    340341        return locked;
     
    368369        wdata.wu_event.inlist = true;
    369370
    370         futex_down(&async_futex);
     371        futex_lock(&async_futex);
    371372        if (timeout) {
    372373                getuptime(&wdata.to_event.expires);
     
    376377        list_append(&wdata.wu_event.link, &fcv->waiters);
    377378        _fibril_mutex_unlock_unsafe(fm);
    378         fibril_switch(FIBRIL_TO_MANAGER);
     379        fibril_switch(FIBRIL_FROM_BLOCKED);
     380        futex_unlock(&async_futex);
     381
     382        // XXX: This could be replaced with an unlocked version to get rid
     383        // of the unlock-lock pair. I deliberately don't do that because
     384        // further changes would most likely need to revert that optimization.
    379385        fibril_mutex_lock(fm);
    380386
    381         /* async_futex not held after fibril_switch() */
    382         futex_down(&async_futex);
     387        futex_lock(&async_futex);
    383388        if (wdata.to_event.inlist)
    384389                list_remove(&wdata.to_event.link);
    385390        if (wdata.wu_event.inlist)
    386391                list_remove(&wdata.wu_event.link);
    387         futex_up(&async_futex);
     392        futex_unlock(&async_futex);
    388393
    389394        return wdata.to_event.occurred ? ETIMEOUT : EOK;
     
    403408        awaiter_t *wdp;
    404409
    405         futex_down(&async_futex);
     410        futex_lock(&async_futex);
    406411        while (!list_empty(&fcv->waiters)) {
    407412                tmp = list_first(&fcv->waiters);
     
    417422                }
    418423        }
    419         futex_up(&async_futex);
     424        futex_unlock(&async_futex);
    420425}
    421426
     
    656661void fibril_semaphore_up(fibril_semaphore_t *sem)
    657662{
    658         futex_down(&async_futex);
     663        futex_lock(&async_futex);
    659664        sem->count++;
    660665
    661666        if (sem->count > 0) {
    662                 futex_up(&async_futex);
     667                futex_unlock(&async_futex);
    663668                return;
    664669        }
     
    668673        list_remove(tmp);
    669674
    670         futex_up(&async_futex);
     675        futex_unlock(&async_futex);
    671676
    672677        awaiter_t *wdp = list_get_instance(tmp, awaiter_t, wu_event.link);
     
    684689void fibril_semaphore_down(fibril_semaphore_t *sem)
    685690{
    686         futex_down(&async_futex);
     691        futex_lock(&async_futex);
    687692        sem->count--;
    688693
    689694        if (sem->count >= 0) {
    690                 futex_up(&async_futex);
     695                futex_unlock(&async_futex);
    691696                return;
    692697        }
     
    697702        wdata.fid = fibril_get_id();
    698703        list_append(&wdata.wu_event.link, &sem->waiters);
    699         fibril_switch(FIBRIL_TO_MANAGER);
    700 
    701         /* async_futex not held after fibril_switch() */
     704
     705        fibril_switch(FIBRIL_FROM_BLOCKED);
     706        futex_unlock(&async_futex);
    702707}
    703708
  • uspace/lib/c/generic/futex.c

    rfbfe59d r8119363  
    3434
    3535#include <futex.h>
     36
     37#include <assert.h>
    3638#include <atomic.h>
     39#include <fibril.h>
     40#include <io/kio.h>
     41
     42#include "private/fibril.h"
     43
     44//#define DPRINTF(...) kio_printf(__VA_ARGS__)
     45#define DPRINTF(...) ((void)0)
    3746
    3847/** Initialize futex counter.
     
    4756}
    4857
     58#ifdef CONFIG_DEBUG_FUTEX
    4959
    50 #ifdef FUTEX_UPGRADABLE
     60void __futex_assert_is_locked(futex_t *futex, const char *name)
     61{
     62        void *owner = __atomic_load_n(&futex->owner, __ATOMIC_RELAXED);
     63        fibril_t *self = (fibril_t *) fibril_get_id();
     64        if (owner != self) {
     65                DPRINTF("Assertion failed: %s (%p) is not locked by fibril %p (instead locked by fibril %p).\n", name, futex, self, owner);
     66        }
     67        assert(owner == self);
     68}
    5169
    52 int _upgrade_futexes = 0;
    53 static futex_t upg_and_wait_futex = FUTEX_INITIALIZER;
     70void __futex_assert_is_not_locked(futex_t *futex, const char *name)
     71{
     72        void *owner = __atomic_load_n(&futex->owner, __ATOMIC_RELAXED);
     73        fibril_t *self = (fibril_t *) fibril_get_id();
     74        if (owner == self) {
     75                DPRINTF("Assertion failed: %s (%p) is already locked by fibril %p.\n", name, futex, self);
     76        }
     77        assert(owner != self);
     78}
    5479
    55 void futex_upgrade_all_and_wait(void)
     80void __futex_lock(futex_t *futex, const char *name)
    5681{
    57         futex_down(&upg_and_wait_futex);
     82        /* We use relaxed atomics to avoid violating C11 memory model.
     83         * They should compile to regular load/stores, but simple assignments
     84         * would be UB by definition.
     85         */
    5886
    59         if (!_upgrade_futexes) {
    60                 rcu_assign(_upgrade_futexes, 1);
    61                 _rcu_synchronize(BM_BLOCK_THREAD);
     87        fibril_t *self = (fibril_t *) fibril_get_id();
     88        DPRINTF("Locking futex %s (%p) by fibril %p.\n", name, futex, self);
     89        __futex_assert_is_not_locked(futex, name);
     90        futex_down(futex);
     91
     92        void *prev_owner = __atomic_exchange_n(&futex->owner, self, __ATOMIC_RELAXED);
     93        assert(prev_owner == NULL);
     94
     95        atomic_inc(&self->futex_locks);
     96}
     97
     98void __futex_unlock(futex_t *futex, const char *name)
     99{
     100        fibril_t *self = (fibril_t *) fibril_get_id();
     101        DPRINTF("Unlocking futex %s (%p) by fibril %p.\n", name, futex, self);
     102        __futex_assert_is_locked(futex, name);
     103        __atomic_store_n(&futex->owner, NULL, __ATOMIC_RELAXED);
     104        atomic_dec(&self->futex_locks);
     105        futex_up(futex);
     106}
     107
     108bool __futex_trylock(futex_t *futex, const char *name)
     109{
     110        fibril_t *self = (fibril_t *) fibril_get_id();
     111        bool success = futex_trydown(futex);
     112        if (success) {
     113                void *owner = __atomic_load_n(&futex->owner, __ATOMIC_RELAXED);
     114                assert(owner == NULL);
     115
     116                __atomic_store_n(&futex->owner, self, __ATOMIC_RELAXED);
     117
     118                atomic_inc(&self->futex_locks);
     119
     120                DPRINTF("Trylock on futex %s (%p) by fibril %p succeeded.\n", name, futex, self);
     121        } else {
     122                DPRINTF("Trylock on futex %s (%p) by fibril %p failed.\n", name, futex, self);
    62123        }
    63124
    64         futex_up(&upg_and_wait_futex);
     125        return success;
     126}
     127
     128void __futex_give_to(futex_t *futex, void *new_owner, const char *name)
     129{
     130        fibril_t *self = fibril_self();
     131        fibril_t *no = new_owner;
     132        DPRINTF("Passing futex %s (%p) from fibril %p to fibril %p.\n", name, futex, self, no);
     133
     134        __futex_assert_is_locked(futex, name);
     135        atomic_dec(&self->futex_locks);
     136        atomic_inc(&no->futex_locks);
     137        __atomic_store_n(&futex->owner, new_owner, __ATOMIC_RELAXED);
    65138}
    66139
  • uspace/lib/c/generic/inet/host.c

    rfbfe59d r8119363  
    3535 */
    3636
     37#include <assert.h>
    3738#include <errno.h>
    3839#include <inet/addr.h>
  • uspace/lib/c/generic/inet/hostport.c

    rfbfe59d r8119363  
    3636 */
    3737
     38#include <assert.h>
    3839#include <errno.h>
    3940#include <inet/addr.h>
  • uspace/lib/c/generic/libc.c

    rfbfe59d r8119363  
    5555#include "private/malloc.h"
    5656#include "private/io.h"
    57 
    58 #ifdef FUTEX_UPGRADABLE
    59 #include <rcu.h>
    60 #endif
     57#include "private/fibril.h"
    6158
    6259#ifdef CONFIG_RTLD
     
    8986
    9087        __tcb_set(fibril->tcb);
    91 
    92 
    93 #ifdef FUTEX_UPGRADABLE
    94         rcu_register_fibril();
    95 #endif
    9688
    9789        __async_server_init();
  • uspace/lib/c/generic/rcu.c

    rfbfe59d r8119363  
    8282#include <thread.h>
    8383
     84#include "private/fibril.h"
     85
    8486
    8587/** RCU sleeps for RCU_SLEEP_MS before polling an active RCU reader again. */
     
    148150
    149151
    150 static void wait_for_readers(size_t reader_group, blocking_mode_t blocking_mode);
     152static void wait_for_readers(size_t reader_group);
    151153static void force_mb_in_all_threads(void);
    152154static bool is_preexisting_reader(const fibril_rcu_data_t *fib, size_t group);
    153155
    154 static void lock_sync(blocking_mode_t blocking_mode);
     156static void lock_sync(void);
    155157static void unlock_sync(void);
    156 static void sync_sleep(blocking_mode_t blocking_mode);
     158static void sync_sleep(void);
    157159
    158160static bool is_in_group(size_t nesting_cnt, size_t group);
     
    170172        assert(!fibril_rcu.registered);
    171173
    172         futex_down(&rcu.list_futex);
     174        futex_lock(&rcu.list_futex);
    173175        list_append(&fibril_rcu.link, &rcu.fibrils_list);
    174         futex_up(&rcu.list_futex);
     176        futex_unlock(&rcu.list_futex);
    175177
    176178        fibril_rcu.registered = true;
     
    195197        fibril_rcu.nesting_cnt = 0;
    196198
    197         futex_down(&rcu.list_futex);
     199        futex_lock(&rcu.list_futex);
    198200        list_remove(&fibril_rcu.link);
    199         futex_up(&rcu.list_futex);
     201        futex_unlock(&rcu.list_futex);
    200202
    201203        fibril_rcu.registered = false;
     
    240242
    241243/** Blocks until all preexisting readers exit their critical sections. */
    242 void _rcu_synchronize(blocking_mode_t blocking_mode)
     244void rcu_synchronize(void)
    243245{
    244246        assert(!rcu_read_locked());
     
    250252        size_t gp_in_progress = ACCESS_ONCE(rcu.cur_gp);
    251253
    252         lock_sync(blocking_mode);
     254        lock_sync();
    253255
    254256        /*
     
    298300
    299301        size_t new_reader_group = get_other_group(rcu.reader_group);
    300         wait_for_readers(new_reader_group, blocking_mode);
     302        wait_for_readers(new_reader_group);
    301303
    302304        /* Separates waiting for readers in new_reader_group from group flip. */
     
    310312        memory_barrier();
    311313
    312         wait_for_readers(old_reader_group, blocking_mode);
     314        wait_for_readers(old_reader_group);
    313315
    314316        /* MB_FORCE_U  */
     
    330332
    331333/** Waits for readers of reader_group to exit their readers sections. */
    332 static void wait_for_readers(size_t reader_group, blocking_mode_t blocking_mode)
    333 {
    334         futex_down(&rcu.list_futex);
     334static void wait_for_readers(size_t reader_group)
     335{
     336        futex_lock(&rcu.list_futex);
    335337
    336338        list_t quiescent_fibrils;
     
    343345
    344346                        if (is_preexisting_reader(fib, reader_group)) {
    345                                 futex_up(&rcu.list_futex);
    346                                 sync_sleep(blocking_mode);
    347                                 futex_down(&rcu.list_futex);
     347                                futex_unlock(&rcu.list_futex);
     348                                sync_sleep();
     349                                futex_lock(&rcu.list_futex);
    348350                                /* Break to while loop. */
    349351                                break;
     
    356358
    357359        list_concat(&rcu.fibrils_list, &quiescent_fibrils);
    358         futex_up(&rcu.list_futex);
    359 }
    360 
    361 static void lock_sync(blocking_mode_t blocking_mode)
    362 {
    363         futex_down(&rcu.sync_lock.futex);
     360        futex_unlock(&rcu.list_futex);
     361}
     362
     363static void lock_sync(void)
     364{
     365        futex_lock(&rcu.sync_lock.futex);
    364366        if (rcu.sync_lock.locked) {
    365                 if (blocking_mode == BM_BLOCK_FIBRIL) {
    366                         blocked_fibril_t blocked_fib;
    367                         blocked_fib.id = fibril_get_id();
    368 
    369                         list_append(&blocked_fib.link, &rcu.sync_lock.blocked_fibrils);
    370 
    371                         do {
    372                                 blocked_fib.is_ready = false;
    373                                 futex_up(&rcu.sync_lock.futex);
    374                                 fibril_switch(FIBRIL_TO_MANAGER);
    375                                 futex_down(&rcu.sync_lock.futex);
    376                         } while (rcu.sync_lock.locked);
    377 
    378                         list_remove(&blocked_fib.link);
    379                         rcu.sync_lock.locked = true;
    380                 } else {
    381                         assert(blocking_mode == BM_BLOCK_THREAD);
    382                         rcu.sync_lock.blocked_thread_cnt++;
    383                         futex_up(&rcu.sync_lock.futex);
    384                         futex_down(&rcu.sync_lock.futex_blocking_threads);
    385                 }
     367                blocked_fibril_t blocked_fib;
     368                blocked_fib.id = fibril_get_id();
     369
     370                list_append(&blocked_fib.link, &rcu.sync_lock.blocked_fibrils);
     371
     372                do {
     373                        blocked_fib.is_ready = false;
     374                        futex_unlock(&rcu.sync_lock.futex);
     375                        futex_lock(&async_futex);
     376                        fibril_switch(FIBRIL_FROM_BLOCKED);
     377                        futex_unlock(&async_futex);
     378                        futex_lock(&rcu.sync_lock.futex);
     379                } while (rcu.sync_lock.locked);
     380
     381                list_remove(&blocked_fib.link);
     382                rcu.sync_lock.locked = true;
    386383        } else {
    387384                rcu.sync_lock.locked = true;
     
    399396        if (0 < rcu.sync_lock.blocked_thread_cnt) {
    400397                --rcu.sync_lock.blocked_thread_cnt;
    401                 futex_up(&rcu.sync_lock.futex_blocking_threads);
     398                futex_unlock(&rcu.sync_lock.futex_blocking_threads);
    402399        } else {
    403400                /* Unlock but wake up any fibrils waiting for the lock. */
     
    414411
    415412                rcu.sync_lock.locked = false;
    416                 futex_up(&rcu.sync_lock.futex);
     413                futex_unlock(&rcu.sync_lock.futex);
    417414        }
    418415}
    419416
    420 static void sync_sleep(blocking_mode_t blocking_mode)
     417static void sync_sleep(void)
    421418{
    422419        assert(rcu.sync_lock.locked);
     
    425422         * but keep sync locked.
    426423         */
    427         futex_up(&rcu.sync_lock.futex);
    428 
    429         if (blocking_mode == BM_BLOCK_FIBRIL) {
    430                 async_usleep(RCU_SLEEP_MS * 1000);
    431         } else {
    432                 thread_usleep(RCU_SLEEP_MS * 1000);
    433         }
    434 
    435         futex_down(&rcu.sync_lock.futex);
     424        futex_unlock(&rcu.sync_lock.futex);
     425        async_usleep(RCU_SLEEP_MS * 1000);
     426        futex_lock(&rcu.sync_lock.futex);
    436427}
    437428
  • uspace/lib/c/generic/stacktrace.c

    rfbfe59d r8119363  
    3939#include <stdint.h>
    4040#include <errno.h>
     41#include <io/kio.h>
    4142
    4243static errno_t stacktrace_read_uintptr(void *arg, uintptr_t addr, uintptr_t *data);
    4344
    4445static stacktrace_ops_t basic_ops = {
    45         .read_uintptr = stacktrace_read_uintptr
     46        .read_uintptr = stacktrace_read_uintptr,
     47        .printf = printf,
     48};
     49
     50static stacktrace_ops_t kio_ops = {
     51        .read_uintptr = stacktrace_read_uintptr,
     52        .printf = kio_printf,
    4653};
    4754
     
    5764
    5865        while (stacktrace_fp_valid(&st, fp)) {
    59                 printf("%p: %p()\n", (void *) fp, (void *) pc);
     66                ops->printf("%p: %p()\n", (void *) fp, (void *) pc);
    6067                rc =  stacktrace_ra_get(&st, fp, &pc);
    6168                if (rc != EOK)
     
    7178{
    7279        stacktrace_print_generic(&basic_ops, NULL, fp, pc);
     80}
     81
     82void stacktrace_kio_print(void)
     83{
     84        stacktrace_prepare();
     85        stacktrace_print_generic(&kio_ops, NULL, stacktrace_fp_get(), stacktrace_pc_get());
     86
     87        /*
     88         * Prevent the tail call optimization of the previous call by
     89         * making it a non-tail call.
     90         */
     91
     92        kio_printf("-- end of stack trace --\n");
    7393}
    7494
  • uspace/lib/c/generic/thread.c

    rfbfe59d r8119363  
    4646#include <as.h>
    4747#include "private/thread.h"
    48 
    49 #ifdef FUTEX_UPGRADABLE
    50 #include <rcu.h>
    51 #endif
    52 
     48#include "private/fibril.h"
    5349
    5450/** Main thread function.
     
    6864
    6965        __tcb_set(fibril->tcb);
    70 
    71 #ifdef FUTEX_UPGRADABLE
    72         rcu_register_fibril();
    73         futex_upgrade_all_and_wait();
    74 #endif
    7566
    7667        uarg->uspace_thread_function(uarg->uspace_thread_arg);
     
    8475        /* If there is a manager, destroy it */
    8576        async_destroy_manager();
    86 
    87 #ifdef FUTEX_UPGRADABLE
    88         rcu_deregister_fibril();
    89 #endif
    9077
    9178        fibril_teardown(fibril, false);
  • uspace/lib/c/generic/time.c

    rfbfe59d r8119363  
    5151#include <loc.h>
    5252#include <device/clock_dev.h>
    53 #include <thread.h>
    5453
    5554#define ASCTIME_BUF_LEN  26
     
    487486 * @param tv2 Second timeval.
    488487 */
    489 void tv_add(struct timeval *tv1, struct timeval *tv2)
     488void tv_add(struct timeval *tv1, const struct timeval *tv2)
    490489{
    491490        tv1->tv_sec += tv2->tv_sec;
     
    503502 *
    504503 */
    505 suseconds_t tv_sub_diff(struct timeval *tv1, struct timeval *tv2)
     504suseconds_t tv_sub_diff(const struct timeval *tv1, const struct timeval *tv2)
    506505{
    507506        return (tv1->tv_usec - tv2->tv_usec) +
     
    515514 *
    516515 */
    517 void tv_sub(struct timeval *tv1, struct timeval *tv2)
     516void tv_sub(struct timeval *tv1, const struct timeval *tv2)
    518517{
    519518        tv1->tv_sec -= tv2->tv_sec;
     
    531530 *
    532531 */
    533 int tv_gt(struct timeval *tv1, struct timeval *tv2)
     532int tv_gt(const struct timeval *tv1, const struct timeval *tv2)
    534533{
    535534        if (tv1->tv_sec > tv2->tv_sec)
     
    551550 *
    552551 */
    553 int tv_gteq(struct timeval *tv1, struct timeval *tv2)
     552int tv_gteq(const struct timeval *tv1, const struct timeval *tv2)
    554553{
    555554        if (tv1->tv_sec > tv2->tv_sec)
  • uspace/lib/c/include/async.h

    rfbfe59d r8119363  
    108108typedef struct async_exch async_exch_t;
    109109
    110 #define async_manager() \
    111         do { \
    112                 futex_down(&async_futex); \
    113                 fibril_switch(FIBRIL_FROM_DEAD); \
    114         } while (0)
     110extern _Noreturn void async_manager(void);
    115111
    116112#define async_get_call(data) \
  • uspace/lib/c/include/fibril.h

    rfbfe59d r8119363  
    3636#define LIBC_FIBRIL_H_
    3737
    38 #include <context.h>
    3938#include <types/common.h>
    40 #include <adt/list.h>
    41 #include <libarch/tls.h>
    4239
    43 #define FIBRIL_WRITER   1
    44 
    45 struct fibril;
     40typedef struct fibril fibril_t;
    4641
    4742typedef struct {
    48         struct fibril *owned_by;
     43        fibril_t *owned_by;
    4944} fibril_owner_info_t;
    5045
    51 typedef enum {
    52         FIBRIL_PREEMPT,
    53         FIBRIL_TO_MANAGER,
    54         FIBRIL_FROM_MANAGER,
    55         FIBRIL_FROM_DEAD
    56 } fibril_switch_type_t;
    57 
    5846typedef sysarg_t fid_t;
    59 
    60 typedef struct fibril {
    61         link_t link;
    62         link_t all_link;
    63         context_t ctx;
    64         void *stack;
    65         void *arg;
    66         errno_t (*func)(void *);
    67         tcb_t *tcb;
    68 
    69         struct fibril *clean_after_me;
    70         errno_t retval;
    71         int flags;
    72 
    73         fibril_owner_info_t *waits_for;
    74 } fibril_t;
    7547
    7648/** Fibril-local variable specifier */
     
    8153extern fid_t fibril_create_generic(errno_t (*func)(void *), void *arg, size_t);
    8254extern void fibril_destroy(fid_t fid);
    83 extern fibril_t *fibril_setup(void);
    84 extern void fibril_teardown(fibril_t *f, bool locked);
    85 extern int fibril_switch(fibril_switch_type_t stype);
    8655extern void fibril_add_ready(fid_t fid);
    87 extern void fibril_add_manager(fid_t fid);
    88 extern void fibril_remove_manager(void);
    8956extern fid_t fibril_get_id(void);
     57extern void fibril_yield(void);
    9058
    9159static inline fid_t fibril_create(errno_t (*func)(void *), void *arg)
     
    9462}
    9563
    96 static inline int fibril_yield(void)
    97 {
    98         return fibril_switch(FIBRIL_PREEMPT);
    99 }
    100 
    10164#endif
    10265
  • uspace/lib/c/include/futex.h

    rfbfe59d r8119363  
    3636#define LIBC_FUTEX_H_
    3737
     38#include <assert.h>
    3839#include <atomic.h>
    3940#include <errno.h>
    4041#include <libc.h>
     42#include <time.h>
    4143
    4244typedef struct futex {
    4345        atomic_t val;
    44 #ifdef FUTEX_UPGRADABLE
    45         int upgraded;
     46#ifdef CONFIG_DEBUG_FUTEX
     47        _Atomic void *owner;
    4648#endif
    4749} futex_t;
    4850
    49 
    5051extern void futex_initialize(futex_t *futex, int value);
    5152
    52 #ifdef FUTEX_UPGRADABLE
    53 #include <rcu.h>
     53#ifdef CONFIG_DEBUG_FUTEX
    5454
    55 #define FUTEX_INITIALIZE(val) {{ (val) }, 0}
     55#define FUTEX_INITIALIZE(val) {{ (val) }, NULL }
     56#define FUTEX_INITIALIZER     FUTEX_INITIALIZE(1)
    5657
    57 #define futex_lock(fut) \
    58 ({ \
    59         rcu_read_lock(); \
    60         (fut)->upgraded = rcu_access(_upgrade_futexes); \
    61         if ((fut)->upgraded) \
    62                 (void) futex_down((fut)); \
    63 })
     58void __futex_assert_is_locked(futex_t *, const char *);
     59void __futex_assert_is_not_locked(futex_t *, const char *);
     60void __futex_lock(futex_t *, const char *);
     61void __futex_unlock(futex_t *, const char *);
     62bool __futex_trylock(futex_t *, const char *);
     63void __futex_give_to(futex_t *, void *, const char *);
    6464
    65 #define futex_trylock(fut) \
    66 ({ \
    67         rcu_read_lock(); \
    68         int _upgraded = rcu_access(_upgrade_futexes); \
    69         if (_upgraded) { \
    70                 int _acquired = futex_trydown((fut)); \
    71                 if (!_acquired) { \
    72                         rcu_read_unlock(); \
    73                 } else { \
    74                         (fut)->upgraded = true; \
    75                 } \
    76                 _acquired; \
    77         } else { \
    78                 (fut)->upgraded = false; \
    79                 1; \
    80         } \
    81 })
     65#define futex_lock(futex) __futex_lock((futex), #futex)
     66#define futex_unlock(futex) __futex_unlock((futex), #futex)
     67#define futex_trylock(futex) __futex_trylock((futex), #futex)
    8268
    83 #define futex_unlock(fut) \
    84 ({ \
    85         if ((fut)->upgraded) \
    86                 (void) futex_up((fut)); \
    87         rcu_read_unlock(); \
    88 })
    89 
    90 extern int _upgrade_futexes;
    91 
    92 extern void futex_upgrade_all_and_wait(void);
     69#define futex_give_to(futex, new_owner) __futex_give_to((futex), (new_owner), #futex)
     70#define futex_assert_is_locked(futex) __futex_assert_is_locked((futex), #futex)
     71#define futex_assert_is_not_locked(futex) __futex_assert_is_not_locked((futex), #futex)
    9372
    9473#else
    9574
    9675#define FUTEX_INITIALIZE(val) {{ (val) }}
     76#define FUTEX_INITIALIZER     FUTEX_INITIALIZE(1)
    9777
    9878#define futex_lock(fut)     (void) futex_down((fut))
     
    10080#define futex_unlock(fut)   (void) futex_up((fut))
    10181
     82#define futex_give_to(fut, owner) ((void)0)
     83#define futex_assert_is_locked(fut) assert((atomic_signed_t) (fut)->val.count <= 0)
     84#define futex_assert_is_not_locked(fut) ((void)0)
     85
    10286#endif
    103 
    104 #define FUTEX_INITIALIZER     FUTEX_INITIALIZE(1)
    10587
    10688/** Try to down the futex.
     
    11799}
    118100
    119 /** Down the futex.
     101/** Down the futex with timeout, composably.
     102 *
     103 * This means that when the operation fails due to a timeout or being
     104 * interrupted, the next futex_up() is ignored, which allows certain kinds of
     105 * composition of synchronization primitives.
     106 *
     107 * In most other circumstances, regular futex_down_timeout() is a better choice.
    120108 *
    121109 * @param futex Futex.
    122110 *
    123111 * @return ENOENT if there is no such virtual address.
     112 * @return ETIMEOUT if timeout expires.
    124113 * @return EOK on success.
    125114 * @return Error code from <errno.h> otherwise.
    126115 *
    127116 */
    128 static inline errno_t futex_down(futex_t *futex)
     117static inline errno_t futex_down_composable(futex_t *futex, struct timeval *expires)
    129118{
     119        // TODO: Add tests for this.
     120
     121        /* No timeout by default. */
     122        suseconds_t timeout = 0;
     123
     124        if (expires) {
     125                struct timeval tv;
     126                getuptime(&tv);
     127                if (tv_gteq(&tv, expires)) {
     128                        /* We can't just return ETIMEOUT. That wouldn't be composable. */
     129                        timeout = 1;
     130                } else {
     131                        timeout = tv_sub_diff(expires, &tv);
     132                }
     133
     134                assert(timeout > 0);
     135        }
     136
    130137        if ((atomic_signed_t) atomic_predec(&futex->val) < 0)
    131                 return (errno_t) __SYSCALL1(SYS_FUTEX_SLEEP, (sysarg_t) &futex->val.count);
     138                return (errno_t) __SYSCALL2(SYS_FUTEX_SLEEP, (sysarg_t) &futex->val.count, (sysarg_t) timeout);
    132139
    133140        return EOK;
     
    151158}
    152159
     160static inline errno_t futex_down_timeout(futex_t *futex, struct timeval *expires)
     161{
     162        /*
     163         * This combination of a "composable" sleep followed by futex_up() on
     164         * failure is necessary to prevent breakage due to certain race
     165         * conditions.
     166         */
     167        errno_t rc = futex_down_composable(futex, expires);
     168        if (rc != EOK)
     169                futex_up(futex);
     170        return rc;
     171}
     172
     173/** Down the futex.
     174 *
     175 * @param futex Futex.
     176 *
     177 * @return ENOENT if there is no such virtual address.
     178 * @return EOK on success.
     179 * @return Error code from <errno.h> otherwise.
     180 *
     181 */
     182static inline errno_t futex_down(futex_t *futex)
     183{
     184        return futex_down_timeout(futex, NULL);
     185}
     186
    153187#endif
    154188
  • uspace/lib/c/include/rcu.h

    rfbfe59d r8119363  
    9292#define rcu_access(ptr) ACCESS_ONCE(ptr)
    9393
    94 typedef enum blocking_mode {
    95         BM_BLOCK_FIBRIL,
    96         BM_BLOCK_THREAD
    97 } blocking_mode_t;
    98 
    9994extern void rcu_register_fibril(void);
    10095extern void rcu_deregister_fibril(void);
     
    105100extern bool rcu_read_locked(void);
    106101
    107 #define rcu_synchronize() _rcu_synchronize(BM_BLOCK_FIBRIL)
    108 
    109 extern void _rcu_synchronize(blocking_mode_t);
     102extern void rcu_synchronize(void);
    110103
    111104#endif
  • uspace/lib/c/include/stacktrace.h

    rfbfe59d r8119363  
    4343typedef struct {
    4444        errno_t (*read_uintptr)(void *, uintptr_t, uintptr_t *);
     45        int (*printf)(const char *, ...);
    4546} stacktrace_ops_t;
    4647
     
    5152
    5253extern void stacktrace_print(void);
     54extern void stacktrace_kio_print(void);
    5355extern void stacktrace_print_fp_pc(uintptr_t, uintptr_t);
    5456extern void stacktrace_print_generic(stacktrace_ops_t *, void *, uintptr_t,
  • uspace/lib/c/include/sys/time.h

    rfbfe59d r8119363  
    6969};
    7070
     71#define TIMEVAL_MAX ((struct timeval) { .tv_sec = LONG_MAX, .tv_usec = 999999 })
     72
    7173struct timezone {
    7274        int tz_minuteswest;  /* minutes W of Greenwich */
     
    7577
    7678extern void tv_add_diff(struct timeval *, suseconds_t);
    77 extern void tv_add(struct timeval *, struct timeval *);
    78 extern suseconds_t tv_sub_diff(struct timeval *, struct timeval *);
    79 extern void tv_sub(struct timeval *, struct timeval *);
    80 extern int tv_gt(struct timeval *, struct timeval *);
    81 extern int tv_gteq(struct timeval *, struct timeval *);
     79extern void tv_add(struct timeval *, const struct timeval *);
     80extern suseconds_t tv_sub_diff(const struct timeval *, const struct timeval *);
     81extern void tv_sub(struct timeval *, const struct timeval *);
     82extern int tv_gt(const struct timeval *, const struct timeval *);
     83extern int tv_gteq(const struct timeval *, const struct timeval *);
    8284extern void gettimeofday(struct timeval *, struct timezone *);
    8385extern void getuptime(struct timeval *);
  • uspace/srv/volsrv/types/part.h

    rfbfe59d r8119363  
    3838#define TYPES_PART_H_
    3939
     40#include <adt/list.h>
    4041#include <types/label.h>
    4142
Note: See TracChangeset for help on using the changeset viewer.