Changes in / [8119363:fbfe59d] in mainline


Ignore:
Files:
1 deleted
30 edited

Legend:

Unmodified
Added
Removed
  • HelenOS.config

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

    r8119363 rfbfe59d  
    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)
    4947
    5048#endif
  • kernel/generic/include/proc/thread.h

    r8119363 rfbfe59d  
    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 
    122114        /** Wait queue in which this thread sleeps. */
    123115        waitq_t *sleep_queue;
  • kernel/generic/include/synch/futex.h

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

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

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

    r8119363 rfbfe59d  
    398398}
    399399
    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.
     400/** Sleep in futex wait queue.
     401 *
     402 * @param uaddr         Userspace address of the futex counter.
    406403 *
    407404 * @return              If there is no physical mapping for uaddr ENOENT is
     
    409406 *                      waitq_sleep_timeout().
    410407 */
    411 sys_errno_t sys_futex_sleep(uintptr_t uaddr, uintptr_t timeout)
     408sys_errno_t sys_futex_sleep(uintptr_t uaddr)
    412409{
    413410        futex_t *futex = get_futex(uaddr);
     
    420417#endif
    421418
    422         errno_t rc = waitq_sleep_timeout(&futex->wq, timeout,
    423             SYNCH_FLAGS_INTERRUPTIBLE | SYNCH_FLAGS_FUTEX, NULL);
     419        errno_t rc = waitq_sleep_timeout(
     420            &futex->wq, 0, SYNCH_FLAGS_INTERRUPTIBLE, NULL);
    424421
    425422#ifdef CONFIG_UDEBUG
  • kernel/generic/src/synch/waitq.c

    r8119363 rfbfe59d  
    5757#include <adt/list.h>
    5858#include <arch/cycle.h>
    59 #include <mem.h>
    6059
    6160static void waitq_sleep_timed_out(void *);
     
    7271void waitq_initialize(waitq_t *wq)
    7372{
    74         memsetb(wq, sizeof(*wq), 0);
    7573        irq_spinlock_initialize(&wq->lock, "wq.lock");
    7674        list_initialize(&wq->sleepers);
     75        wq->missed_wakeups = 0;
    7776}
    7877
     
    115114                thread->saved_context = thread->sleep_timeout_context;
    116115                do_wakeup = true;
    117                 if (thread->sleep_composable)
    118                         wq->ignore_wakeups++;
    119116                thread->sleep_queue = NULL;
    120117                irq_spinlock_unlock(&wq->lock, false);
     
    179176                list_remove(&thread->wq_link);
    180177                thread->saved_context = thread->sleep_interruption_context;
    181                 if (thread->sleep_composable)
    182                         wq->ignore_wakeups++;
    183178                do_wakeup = true;
    184179                thread->sleep_queue = NULL;
     
    398393         */
    399394        irq_spinlock_lock(&THREAD->lock, false);
    400 
    401         THREAD->sleep_composable = (flags & SYNCH_FLAGS_FUTEX);
    402395
    403396        if (flags & SYNCH_FLAGS_INTERRUPTIBLE) {
     
    545538        assert(irq_spinlock_locked(&wq->lock));
    546539
    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 
    555540loop:
    556541        if (list_empty(&wq->sleepers)) {
  • uspace/app/nic/nic.c

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

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

    r8119363 rfbfe59d  
    3838#include <stacktrace.h>
    3939#include <stdint.h>
    40 #include <task.h>
    4140
    4241static atomic_t failed_asserts = { 0 };
     
    4746         * Send the message safely to kio. Nested asserts should not occur.
    4847         */
    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();
     48        kio_printf("Assertion failed (%s) in file \"%s\", line %u.\n",
     49            cond, file, line);
    5350
    5451        /* Sometimes we know in advance that regular printf() would likely fail. */
     
    6158         * Send the message safely to kio. Nested asserts should not occur.
    6259         */
    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();
     60        kio_printf("Assertion failed (%s) in file \"%s\", line %u.\n",
     61            cond, file, line);
    6762
    6863        /*
     
    7772         * assertions.
    7873         */
    79         kio_printf("Assertion failed (%s) in task %ld, file \"%s\", line %u.\n",
    80             cond, (long) task_get_id(), file, line);
     74        printf("Assertion failed (%s) in file \"%s\", line %u.\n",
     75            cond, file, line);
    8176        stacktrace_print();
    8277
  • uspace/lib/c/generic/async/client.c

    r8119363 rfbfe59d  
    121121#include <abi/mm/as.h>
    122122#include "../private/libc.h"
    123 #include "../private/fibril.h"
    124123
    125124/** Naming service session */
     
    242241        assert(arg);
    243242
    244         futex_lock(&async_futex);
     243        futex_down(&async_futex);
    245244
    246245        amsg_t *msg = (amsg_t *) arg;
     
    267266        }
    268267
    269         futex_unlock(&async_futex);
     268        futex_up(&async_futex);
    270269}
    271270
     
    356355        amsg_t *msg = (amsg_t *) amsgid;
    357356
    358         futex_lock(&async_futex);
     357        futex_down(&async_futex);
    359358
    360359        assert(!msg->forget);
     
    362361
    363362        if (msg->done) {
    364                 futex_unlock(&async_futex);
     363                futex_up(&async_futex);
    365364                goto done;
    366365        }
     
    371370
    372371        /* Leave the async_futex locked when entering this function */
    373         fibril_switch(FIBRIL_FROM_BLOCKED);
    374         futex_unlock(&async_futex);
     372        fibril_switch(FIBRIL_TO_MANAGER);
     373
     374        /* Futex is up automatically after fibril_switch */
    375375
    376376done:
     
    401401        amsg_t *msg = (amsg_t *) amsgid;
    402402
    403         futex_lock(&async_futex);
     403        futex_down(&async_futex);
    404404
    405405        assert(!msg->forget);
     
    407407
    408408        if (msg->done) {
    409                 futex_unlock(&async_futex);
     409                futex_up(&async_futex);
    410410                goto done;
    411411        }
     
    443443
    444444        /* Leave the async_futex locked when entering this function */
    445         fibril_switch(FIBRIL_FROM_BLOCKED);
    446         futex_unlock(&async_futex);
     445        fibril_switch(FIBRIL_TO_MANAGER);
     446
     447        /* Futex is up automatically after fibril_switch */
    447448
    448449        if (!msg->done)
     
    474475        assert(!msg->destroyed);
    475476
    476         futex_lock(&async_futex);
     477        futex_down(&async_futex);
    477478
    478479        if (msg->done) {
     
    483484        }
    484485
    485         futex_unlock(&async_futex);
     486        futex_up(&async_futex);
    486487}
    487488
     
    503504        tv_add_diff(&awaiter.to_event.expires, timeout);
    504505
    505         futex_lock(&async_futex);
     506        futex_down(&async_futex);
    506507
    507508        async_insert_timeout(&awaiter);
    508509
    509510        /* Leave the async_futex locked when entering this function */
    510         fibril_switch(FIBRIL_FROM_BLOCKED);
    511         futex_unlock(&async_futex);
     511        fibril_switch(FIBRIL_TO_MANAGER);
     512
     513        /* Futex is up automatically after fibril_switch() */
    512514}
    513515
  • uspace/lib/c/generic/async/server.c

    r8119363 rfbfe59d  
    120120#include <abi/mm/as.h>
    121121#include "../private/libc.h"
    122 #include "../private/fibril.h"
    123122
    124123/** Async framework global futex */
     
    432431         * Remove myself from the connection hash table.
    433432         */
    434         futex_lock(&async_futex);
     433        futex_down(&async_futex);
    435434        hash_table_remove(&conn_hash_table, &(conn_key_t){
    436435                .task_id = fibril_connection->in_task_id,
    437436                .phone_hash = fibril_connection->in_phone_hash
    438437        });
    439         futex_unlock(&async_futex);
     438        futex_up(&async_futex);
    440439
    441440        /*
     
    520519        /* Add connection to the connection hash table */
    521520
    522         futex_lock(&async_futex);
     521        futex_down(&async_futex);
    523522        hash_table_insert(&conn_hash_table, &conn->link);
    524         futex_unlock(&async_futex);
     523        futex_up(&async_futex);
    525524
    526525        fibril_add_ready(conn->wdata.fid);
     
    648647        assert(call);
    649648
    650         futex_lock(&async_futex);
     649        futex_down(&async_futex);
    651650
    652651        ht_link_t *link = hash_table_find(&conn_hash_table, &(conn_key_t){
     
    655654        });
    656655        if (!link) {
    657                 futex_unlock(&async_futex);
     656                futex_up(&async_futex);
    658657                return false;
    659658        }
     
    663662        msg_t *msg = malloc(sizeof(*msg));
    664663        if (!msg) {
    665                 futex_unlock(&async_futex);
     664                futex_up(&async_futex);
    666665                return false;
    667666        }
     
    687686        }
    688687
    689         futex_unlock(&async_futex);
     688        futex_up(&async_futex);
    690689        return true;
    691690}
     
    962961        connection_t *conn = fibril_connection;
    963962
    964         futex_lock(&async_futex);
     963        futex_down(&async_futex);
    965964
    966965        if (usecs) {
     
    982981                        memset(call, 0, sizeof(ipc_call_t));
    983982                        IPC_SET_IMETHOD(*call, IPC_M_PHONE_HUNGUP);
    984                         futex_unlock(&async_futex);
     983                        futex_up(&async_futex);
    985984                        return conn->close_chandle;
    986985                }
     
    997996                 * case, route_call() will perform the wakeup.
    998997                 */
    999                 fibril_switch(FIBRIL_FROM_BLOCKED);
    1000 
     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);
    10011005                if ((usecs) && (conn->wdata.to_event.occurred) &&
    10021006                    (list_empty(&conn->msg_queue))) {
    10031007                        /* If we timed out -> exit */
    1004                         futex_unlock(&async_futex);
     1008                        futex_up(&async_futex);
    10051009                        return CAP_NIL;
    10061010                }
     
    10151019        free(msg);
    10161020
    1017         futex_unlock(&async_futex);
     1021        futex_up(&async_futex);
    10181022        return chandle;
    10191023}
     
    10661070        assert(call);
    10671071
    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                 }
     1072        /* Kernel notification */
     1073        if ((chandle == CAP_NIL) && (call->flags & IPC_CALL_NOTIF)) {
     1074                queue_notification(call);
    10761075                return;
    10771076        }
     
    11011100
    11021101/** Fire all timeouts that expired. */
    1103 static 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 
     1102static void handle_expired_timeouts(void)
     1103{
    11081104        struct timeval tv;
    11091105        getuptime(&tv);
    11101106
    1111         bool fired = false;
     1107        futex_down(&async_futex);
    11121108
    11131109        link_t *cur = list_first(&timeout_list);
     
    11161112                    list_get_instance(cur, awaiter_t, to_event.link);
    11171113
    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                 }
     1114                if (tv_gt(&waiter->to_event.expires, &tv))
     1115                        break;
    11261116
    11271117                list_remove(&waiter->to_event.link);
     
    11361126                        waiter->active = true;
    11371127                        fibril_add_ready(waiter->fid);
    1138                         fired = true;
    11391128                }
    11401129
     
    11421131        }
    11431132
    1144         if (fired) {
    1145                 *flags = SYNCH_FLAGS_NON_BLOCKING;
    1146                 return 0;
    1147         }
    1148 
    1149         return SYNCH_NO_TIMEOUT;
     1133        futex_up(&async_futex);
    11501134}
    11511135
     
    11581142{
    11591143        while (true) {
    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 
     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;
    11681156                unsigned int flags = SYNCH_FLAGS_NONE;
    1169                 suseconds_t next_timeout = handle_expired_timeouts(&flags);
    1170                 futex_unlock(&async_futex);
     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                }
    11711189
    11721190                atomic_inc(&threads_in_ipc_wait);
    11731191
    11741192                ipc_call_t call;
    1175                 errno_t rc = ipc_wait_cycle(&call, next_timeout, flags);
     1193                errno_t rc = ipc_wait_cycle(&call, timeout, flags);
    11761194
    11771195                atomic_dec(&threads_in_ipc_wait);
    11781196
    11791197                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
    11801211                handle_call(call.cap_handle, &call);
    11811212        }
     
    11941225static errno_t async_manager_fibril(void *arg)
    11951226{
     1227        futex_up(&async_futex);
     1228
     1229        /*
     1230         * async_futex is always locked when entering manager
     1231         */
    11961232        async_manager_worker();
     1233
    11971234        return 0;
    11981235}
     
    18471884}
    18481885
    1849 _Noreturn void async_manager(void)
    1850 {
    1851         futex_lock(&async_futex);
    1852         fibril_switch(FIBRIL_FROM_DEAD);
    1853         __builtin_unreachable();
    1854 }
    1855 
    18561886/** @}
    18571887 */
  • uspace/lib/c/generic/fibril.c

    r8119363 rfbfe59d  
    4949#include <async.h>
    5050
    51 #include "private/fibril.h"
    52 
     51#ifdef FUTEX_UPGRADABLE
     52#include <rcu.h>
     53#endif
    5354
    5455/**
     
    7172static void fibril_main(void)
    7273{
    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();
     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
    7882
    7983        /* Call the implementing function. */
    8084        fibril->retval = fibril->func(fibril->arg);
    8185
    82         futex_lock(&async_futex);
     86        futex_down(&async_futex);
    8387        fibril_switch(FIBRIL_FROM_DEAD);
    8488        /* Not reached */
     
    9498                return NULL;
    9599
    96         fibril_t *fibril = calloc(1, sizeof(fibril_t));
     100        fibril_t *fibril = malloc(sizeof(fibril_t));
    97101        if (!fibril) {
    98102                tls_free(tcb);
     
    102106        tcb->fibril_data = fibril;
    103107        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;
    104117
    105118        /*
     
    128141/** Switch from the current fibril.
    129142 *
    130  * The async_futex must be held when entering this function,
    131  * and is still held on return.
     143 * If stype is FIBRIL_TO_MANAGER or FIBRIL_FROM_DEAD, the async_futex must
     144 * be held.
    132145 *
    133146 * @param stype Switch type. One of FIBRIL_PREEMPT, FIBRIL_TO_MANAGER,
     
    141154int fibril_switch(fibril_switch_type_t stype)
    142155{
    143         /* Make sure the async_futex is held. */
    144         futex_assert_is_locked(&async_futex);
    145 
    146156        futex_lock(&fibril_futex);
    147157
    148         fibril_t *srcf = fibril_self();
     158        fibril_t *srcf = __tcb_get()->fibril_data;
    149159        fibril_t *dstf = NULL;
    150160
    151161        /* Choose a new fibril to run */
    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                 }
     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);
    159167
    160168                /* If we are going to manager and none exists, create it */
     
    167175                dstf = list_get_instance(list_first(&manager_list),
    168176                    fibril_t, link);
    169         } else {
     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
    170188                dstf = list_get_instance(list_first(&ready_list), fibril_t,
    171189                    link);
    172         }
    173 
     190                break;
     191        }
    174192        list_remove(&dstf->link);
    175         if (stype == FIBRIL_FROM_DEAD)
    176                 dstf->clean_after_me = srcf;
    177193
    178194        /* Put the current fibril into the correct run list */
     
    185201                break;
    186202        case FIBRIL_FROM_DEAD:
    187         case FIBRIL_FROM_BLOCKED:
    188203                // Nothing.
    189204                break;
    190         }
    191 
    192         /* Bookkeeping. */
    193         futex_give_to(&fibril_futex, dstf);
    194         futex_give_to(&async_futex, dstf);
     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
    195218
    196219        /* Swap to the next fibril. */
     
    322345}
    323346
    324 fibril_t *fibril_self(void)
    325 {
    326         return __tcb_get()->fibril_data;
    327 }
    328 
    329347/** Return fibril id of the currently running fibril.
    330348 *
     
    334352fid_t fibril_get_id(void)
    335353{
    336         return (fid_t) fibril_self();
    337 }
    338 
    339 void fibril_yield(void)
    340 {
    341         futex_lock(&async_futex);
    342         (void) fibril_switch(FIBRIL_PREEMPT);
    343         futex_unlock(&async_futex);
     354        return (fid_t) __tcb_get()->fibril_data;
    344355}
    345356
  • uspace/lib/c/generic/fibril_synch.c

    r8119363 rfbfe59d  
    4545#include <stdio.h>
    4646#include "private/async.h"
    47 #include "private/fibril.h"
    4847
    4948static void optimize_execution_power(void)
     
    106105        fibril_t *f = (fibril_t *) fibril_get_id();
    107106
    108         futex_lock(&async_futex);
     107        futex_down(&async_futex);
    109108        if (fm->counter-- <= 0) {
    110109                awaiter_t wdata;
     
    116115                check_for_deadlock(&fm->oi);
    117116                f->waits_for = &fm->oi;
    118                 fibril_switch(FIBRIL_FROM_BLOCKED);
     117                fibril_switch(FIBRIL_TO_MANAGER);
    119118        } else {
    120119                fm->oi.owned_by = f;
    121         }
    122         futex_unlock(&async_futex);
     120                futex_up(&async_futex);
     121        }
    123122}
    124123
     
    127126        bool locked = false;
    128127
    129         futex_lock(&async_futex);
     128        futex_down(&async_futex);
    130129        if (fm->counter > 0) {
    131130                fm->counter--;
     
    133132                locked = true;
    134133        }
    135         futex_unlock(&async_futex);
     134        futex_up(&async_futex);
    136135
    137136        return locked;
     
    166165{
    167166        assert(fibril_mutex_is_locked(fm));
    168         futex_lock(&async_futex);
     167        futex_down(&async_futex);
    169168        _fibril_mutex_unlock_unsafe(fm);
    170         futex_unlock(&async_futex);
     169        futex_up(&async_futex);
    171170}
    172171
     
    175174        bool locked = false;
    176175
    177         futex_lock(&async_futex);
     176        futex_down(&async_futex);
    178177        if (fm->counter <= 0)
    179178                locked = true;
    180         futex_unlock(&async_futex);
     179        futex_up(&async_futex);
    181180
    182181        return locked;
     
    195194        fibril_t *f = (fibril_t *) fibril_get_id();
    196195
    197         futex_lock(&async_futex);
     196        futex_down(&async_futex);
    198197        if (frw->writers) {
    199198                awaiter_t wdata;
     
    202201                wdata.fid = (fid_t) f;
    203202                wdata.wu_event.inlist = true;
    204                 f->is_writer = false;
     203                f->flags &= ~FIBRIL_WRITER;
    205204                list_append(&wdata.wu_event.link, &frw->waiters);
    206205                check_for_deadlock(&frw->oi);
    207206                f->waits_for = &frw->oi;
    208                 fibril_switch(FIBRIL_FROM_BLOCKED);
     207                fibril_switch(FIBRIL_TO_MANAGER);
    209208        } else {
    210209                /* Consider the first reader the owner. */
    211210                if (frw->readers++ == 0)
    212211                        frw->oi.owned_by = f;
    213         }
    214         futex_unlock(&async_futex);
     212                futex_up(&async_futex);
     213        }
    215214}
    216215
     
    219218        fibril_t *f = (fibril_t *) fibril_get_id();
    220219
    221         futex_lock(&async_futex);
     220        futex_down(&async_futex);
    222221        if (frw->writers || frw->readers) {
    223222                awaiter_t wdata;
     
    226225                wdata.fid = (fid_t) f;
    227226                wdata.wu_event.inlist = true;
    228                 f->is_writer = true;
     227                f->flags |= FIBRIL_WRITER;
    229228                list_append(&wdata.wu_event.link, &frw->waiters);
    230229                check_for_deadlock(&frw->oi);
    231230                f->waits_for = &frw->oi;
    232                 fibril_switch(FIBRIL_FROM_BLOCKED);
     231                fibril_switch(FIBRIL_TO_MANAGER);
    233232        } else {
    234233                frw->oi.owned_by = f;
    235234                frw->writers++;
    236         }
    237         futex_unlock(&async_futex);
     235                futex_up(&async_futex);
     236        }
    238237}
    239238
    240239static void _fibril_rwlock_common_unlock(fibril_rwlock_t *frw)
    241240{
    242         futex_lock(&async_futex);
     241        futex_down(&async_futex);
    243242        if (frw->readers) {
    244243                if (--frw->readers) {
     
    277276                f->waits_for = NULL;
    278277
    279                 if (f->is_writer) {
     278                if (f->flags & FIBRIL_WRITER) {
    280279                        if (frw->readers)
    281280                                break;
     
    301300        }
    302301out:
    303         futex_unlock(&async_futex);
     302        futex_up(&async_futex);
    304303}
    305304
     
    320319        bool locked = false;
    321320
    322         futex_lock(&async_futex);
     321        futex_down(&async_futex);
    323322        if (frw->readers)
    324323                locked = true;
    325         futex_unlock(&async_futex);
     324        futex_up(&async_futex);
    326325
    327326        return locked;
     
    332331        bool locked = false;
    333332
    334         futex_lock(&async_futex);
     333        futex_down(&async_futex);
    335334        if (frw->writers) {
    336335                assert(frw->writers == 1);
    337336                locked = true;
    338337        }
    339         futex_unlock(&async_futex);
     338        futex_up(&async_futex);
    340339
    341340        return locked;
     
    369368        wdata.wu_event.inlist = true;
    370369
    371         futex_lock(&async_futex);
     370        futex_down(&async_futex);
    372371        if (timeout) {
    373372                getuptime(&wdata.to_event.expires);
     
    377376        list_append(&wdata.wu_event.link, &fcv->waiters);
    378377        _fibril_mutex_unlock_unsafe(fm);
    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.
     378        fibril_switch(FIBRIL_TO_MANAGER);
    385379        fibril_mutex_lock(fm);
    386380
    387         futex_lock(&async_futex);
     381        /* async_futex not held after fibril_switch() */
     382        futex_down(&async_futex);
    388383        if (wdata.to_event.inlist)
    389384                list_remove(&wdata.to_event.link);
    390385        if (wdata.wu_event.inlist)
    391386                list_remove(&wdata.wu_event.link);
    392         futex_unlock(&async_futex);
     387        futex_up(&async_futex);
    393388
    394389        return wdata.to_event.occurred ? ETIMEOUT : EOK;
     
    408403        awaiter_t *wdp;
    409404
    410         futex_lock(&async_futex);
     405        futex_down(&async_futex);
    411406        while (!list_empty(&fcv->waiters)) {
    412407                tmp = list_first(&fcv->waiters);
     
    422417                }
    423418        }
    424         futex_unlock(&async_futex);
     419        futex_up(&async_futex);
    425420}
    426421
     
    661656void fibril_semaphore_up(fibril_semaphore_t *sem)
    662657{
    663         futex_lock(&async_futex);
     658        futex_down(&async_futex);
    664659        sem->count++;
    665660
    666661        if (sem->count > 0) {
    667                 futex_unlock(&async_futex);
     662                futex_up(&async_futex);
    668663                return;
    669664        }
     
    673668        list_remove(tmp);
    674669
    675         futex_unlock(&async_futex);
     670        futex_up(&async_futex);
    676671
    677672        awaiter_t *wdp = list_get_instance(tmp, awaiter_t, wu_event.link);
     
    689684void fibril_semaphore_down(fibril_semaphore_t *sem)
    690685{
    691         futex_lock(&async_futex);
     686        futex_down(&async_futex);
    692687        sem->count--;
    693688
    694689        if (sem->count >= 0) {
    695                 futex_unlock(&async_futex);
     690                futex_up(&async_futex);
    696691                return;
    697692        }
     
    702697        wdata.fid = fibril_get_id();
    703698        list_append(&wdata.wu_event.link, &sem->waiters);
    704 
    705         fibril_switch(FIBRIL_FROM_BLOCKED);
    706         futex_unlock(&async_futex);
     699        fibril_switch(FIBRIL_TO_MANAGER);
     700
     701        /* async_futex not held after fibril_switch() */
    707702}
    708703
  • uspace/lib/c/generic/futex.c

    r8119363 rfbfe59d  
    3434
    3535#include <futex.h>
    36 
    37 #include <assert.h>
    3836#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)
    4637
    4738/** Initialize futex counter.
     
    5647}
    5748
    58 #ifdef CONFIG_DEBUG_FUTEX
    5949
    60 void __futex_assert_is_locked(futex_t *futex, const char *name)
     50#ifdef FUTEX_UPGRADABLE
     51
     52int _upgrade_futexes = 0;
     53static futex_t upg_and_wait_futex = FUTEX_INITIALIZER;
     54
     55void futex_upgrade_all_and_wait(void)
    6156{
    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 }
     57        futex_down(&upg_and_wait_futex);
    6958
    70 void __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 }
    79 
    80 void __futex_lock(futex_t *futex, const char *name)
    81 {
    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          */
    86 
    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 
    98 void __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 
    108 bool __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);
     59        if (!_upgrade_futexes) {
     60                rcu_assign(_upgrade_futexes, 1);
     61                _rcu_synchronize(BM_BLOCK_THREAD);
    12362        }
    12463
    125         return success;
    126 }
    127 
    128 void __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);
     64        futex_up(&upg_and_wait_futex);
    13865}
    13966
  • uspace/lib/c/generic/inet/host.c

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

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

    r8119363 rfbfe59d  
    5555#include "private/malloc.h"
    5656#include "private/io.h"
    57 #include "private/fibril.h"
     57
     58#ifdef FUTEX_UPGRADABLE
     59#include <rcu.h>
     60#endif
    5861
    5962#ifdef CONFIG_RTLD
     
    8689
    8790        __tcb_set(fibril->tcb);
     91
     92
     93#ifdef FUTEX_UPGRADABLE
     94        rcu_register_fibril();
     95#endif
    8896
    8997        __async_server_init();
  • uspace/lib/c/generic/rcu.c

    r8119363 rfbfe59d  
    8282#include <thread.h>
    8383
    84 #include "private/fibril.h"
    85 
    8684
    8785/** RCU sleeps for RCU_SLEEP_MS before polling an active RCU reader again. */
     
    150148
    151149
    152 static void wait_for_readers(size_t reader_group);
     150static void wait_for_readers(size_t reader_group, blocking_mode_t blocking_mode);
    153151static void force_mb_in_all_threads(void);
    154152static bool is_preexisting_reader(const fibril_rcu_data_t *fib, size_t group);
    155153
    156 static void lock_sync(void);
     154static void lock_sync(blocking_mode_t blocking_mode);
    157155static void unlock_sync(void);
    158 static void sync_sleep(void);
     156static void sync_sleep(blocking_mode_t blocking_mode);
    159157
    160158static bool is_in_group(size_t nesting_cnt, size_t group);
     
    172170        assert(!fibril_rcu.registered);
    173171
    174         futex_lock(&rcu.list_futex);
     172        futex_down(&rcu.list_futex);
    175173        list_append(&fibril_rcu.link, &rcu.fibrils_list);
    176         futex_unlock(&rcu.list_futex);
     174        futex_up(&rcu.list_futex);
    177175
    178176        fibril_rcu.registered = true;
     
    197195        fibril_rcu.nesting_cnt = 0;
    198196
    199         futex_lock(&rcu.list_futex);
     197        futex_down(&rcu.list_futex);
    200198        list_remove(&fibril_rcu.link);
    201         futex_unlock(&rcu.list_futex);
     199        futex_up(&rcu.list_futex);
    202200
    203201        fibril_rcu.registered = false;
     
    242240
    243241/** Blocks until all preexisting readers exit their critical sections. */
    244 void rcu_synchronize(void)
     242void _rcu_synchronize(blocking_mode_t blocking_mode)
    245243{
    246244        assert(!rcu_read_locked());
     
    252250        size_t gp_in_progress = ACCESS_ONCE(rcu.cur_gp);
    253251
    254         lock_sync();
     252        lock_sync(blocking_mode);
    255253
    256254        /*
     
    300298
    301299        size_t new_reader_group = get_other_group(rcu.reader_group);
    302         wait_for_readers(new_reader_group);
     300        wait_for_readers(new_reader_group, blocking_mode);
    303301
    304302        /* Separates waiting for readers in new_reader_group from group flip. */
     
    312310        memory_barrier();
    313311
    314         wait_for_readers(old_reader_group);
     312        wait_for_readers(old_reader_group, blocking_mode);
    315313
    316314        /* MB_FORCE_U  */
     
    332330
    333331/** Waits for readers of reader_group to exit their readers sections. */
    334 static void wait_for_readers(size_t reader_group)
    335 {
    336         futex_lock(&rcu.list_futex);
     332static void wait_for_readers(size_t reader_group, blocking_mode_t blocking_mode)
     333{
     334        futex_down(&rcu.list_futex);
    337335
    338336        list_t quiescent_fibrils;
     
    345343
    346344                        if (is_preexisting_reader(fib, reader_group)) {
    347                                 futex_unlock(&rcu.list_futex);
    348                                 sync_sleep();
    349                                 futex_lock(&rcu.list_futex);
     345                                futex_up(&rcu.list_futex);
     346                                sync_sleep(blocking_mode);
     347                                futex_down(&rcu.list_futex);
    350348                                /* Break to while loop. */
    351349                                break;
     
    358356
    359357        list_concat(&rcu.fibrils_list, &quiescent_fibrils);
    360         futex_unlock(&rcu.list_futex);
    361 }
    362 
    363 static void lock_sync(void)
    364 {
    365         futex_lock(&rcu.sync_lock.futex);
     358        futex_up(&rcu.list_futex);
     359}
     360
     361static void lock_sync(blocking_mode_t blocking_mode)
     362{
     363        futex_down(&rcu.sync_lock.futex);
    366364        if (rcu.sync_lock.locked) {
    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;
     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                }
    383386        } else {
    384387                rcu.sync_lock.locked = true;
     
    396399        if (0 < rcu.sync_lock.blocked_thread_cnt) {
    397400                --rcu.sync_lock.blocked_thread_cnt;
    398                 futex_unlock(&rcu.sync_lock.futex_blocking_threads);
     401                futex_up(&rcu.sync_lock.futex_blocking_threads);
    399402        } else {
    400403                /* Unlock but wake up any fibrils waiting for the lock. */
     
    411414
    412415                rcu.sync_lock.locked = false;
    413                 futex_unlock(&rcu.sync_lock.futex);
    414         }
    415 }
    416 
    417 static void sync_sleep(void)
     416                futex_up(&rcu.sync_lock.futex);
     417        }
     418}
     419
     420static void sync_sleep(blocking_mode_t blocking_mode)
    418421{
    419422        assert(rcu.sync_lock.locked);
     
    422425         * but keep sync locked.
    423426         */
    424         futex_unlock(&rcu.sync_lock.futex);
    425         async_usleep(RCU_SLEEP_MS * 1000);
    426         futex_lock(&rcu.sync_lock.futex);
     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);
    427436}
    428437
  • uspace/lib/c/generic/stacktrace.c

    r8119363 rfbfe59d  
    3939#include <stdint.h>
    4040#include <errno.h>
    41 #include <io/kio.h>
    4241
    4342static errno_t stacktrace_read_uintptr(void *arg, uintptr_t addr, uintptr_t *data);
    4443
    4544static stacktrace_ops_t basic_ops = {
    46         .read_uintptr = stacktrace_read_uintptr,
    47         .printf = printf,
    48 };
    49 
    50 static stacktrace_ops_t kio_ops = {
    51         .read_uintptr = stacktrace_read_uintptr,
    52         .printf = kio_printf,
     45        .read_uintptr = stacktrace_read_uintptr
    5346};
    5447
     
    6457
    6558        while (stacktrace_fp_valid(&st, fp)) {
    66                 ops->printf("%p: %p()\n", (void *) fp, (void *) pc);
     59                printf("%p: %p()\n", (void *) fp, (void *) pc);
    6760                rc =  stacktrace_ra_get(&st, fp, &pc);
    6861                if (rc != EOK)
     
    7871{
    7972        stacktrace_print_generic(&basic_ops, NULL, fp, pc);
    80 }
    81 
    82 void 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");
    9373}
    9474
  • uspace/lib/c/generic/thread.c

    r8119363 rfbfe59d  
    4646#include <as.h>
    4747#include "private/thread.h"
    48 #include "private/fibril.h"
     48
     49#ifdef FUTEX_UPGRADABLE
     50#include <rcu.h>
     51#endif
     52
    4953
    5054/** Main thread function.
     
    6468
    6569        __tcb_set(fibril->tcb);
     70
     71#ifdef FUTEX_UPGRADABLE
     72        rcu_register_fibril();
     73        futex_upgrade_all_and_wait();
     74#endif
    6675
    6776        uarg->uspace_thread_function(uarg->uspace_thread_arg);
     
    7584        /* If there is a manager, destroy it */
    7685        async_destroy_manager();
     86
     87#ifdef FUTEX_UPGRADABLE
     88        rcu_deregister_fibril();
     89#endif
    7790
    7891        fibril_teardown(fibril, false);
  • uspace/lib/c/generic/time.c

    r8119363 rfbfe59d  
    5151#include <loc.h>
    5252#include <device/clock_dev.h>
     53#include <thread.h>
    5354
    5455#define ASCTIME_BUF_LEN  26
     
    486487 * @param tv2 Second timeval.
    487488 */
    488 void tv_add(struct timeval *tv1, const struct timeval *tv2)
     489void tv_add(struct timeval *tv1, struct timeval *tv2)
    489490{
    490491        tv1->tv_sec += tv2->tv_sec;
     
    502503 *
    503504 */
    504 suseconds_t tv_sub_diff(const struct timeval *tv1, const struct timeval *tv2)
     505suseconds_t tv_sub_diff(struct timeval *tv1, struct timeval *tv2)
    505506{
    506507        return (tv1->tv_usec - tv2->tv_usec) +
     
    514515 *
    515516 */
    516 void tv_sub(struct timeval *tv1, const struct timeval *tv2)
     517void tv_sub(struct timeval *tv1, struct timeval *tv2)
    517518{
    518519        tv1->tv_sec -= tv2->tv_sec;
     
    530531 *
    531532 */
    532 int tv_gt(const struct timeval *tv1, const struct timeval *tv2)
     533int tv_gt(struct timeval *tv1, struct timeval *tv2)
    533534{
    534535        if (tv1->tv_sec > tv2->tv_sec)
     
    550551 *
    551552 */
    552 int tv_gteq(const struct timeval *tv1, const struct timeval *tv2)
     553int tv_gteq(struct timeval *tv1, struct timeval *tv2)
    553554{
    554555        if (tv1->tv_sec > tv2->tv_sec)
  • uspace/lib/c/include/async.h

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

    r8119363 rfbfe59d  
    3636#define LIBC_FIBRIL_H_
    3737
     38#include <context.h>
    3839#include <types/common.h>
     40#include <adt/list.h>
     41#include <libarch/tls.h>
    3942
    40 typedef struct fibril fibril_t;
     43#define FIBRIL_WRITER   1
     44
     45struct fibril;
    4146
    4247typedef struct {
    43         fibril_t *owned_by;
     48        struct fibril *owned_by;
    4449} fibril_owner_info_t;
    4550
     51typedef enum {
     52        FIBRIL_PREEMPT,
     53        FIBRIL_TO_MANAGER,
     54        FIBRIL_FROM_MANAGER,
     55        FIBRIL_FROM_DEAD
     56} fibril_switch_type_t;
     57
    4658typedef sysarg_t fid_t;
     59
     60typedef 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;
    4775
    4876/** Fibril-local variable specifier */
     
    5381extern fid_t fibril_create_generic(errno_t (*func)(void *), void *arg, size_t);
    5482extern void fibril_destroy(fid_t fid);
     83extern fibril_t *fibril_setup(void);
     84extern void fibril_teardown(fibril_t *f, bool locked);
     85extern int fibril_switch(fibril_switch_type_t stype);
    5586extern void fibril_add_ready(fid_t fid);
     87extern void fibril_add_manager(fid_t fid);
     88extern void fibril_remove_manager(void);
    5689extern fid_t fibril_get_id(void);
    57 extern void fibril_yield(void);
    5890
    5991static inline fid_t fibril_create(errno_t (*func)(void *), void *arg)
     
    6294}
    6395
     96static inline int fibril_yield(void)
     97{
     98        return fibril_switch(FIBRIL_PREEMPT);
     99}
     100
    64101#endif
    65102
  • uspace/lib/c/include/futex.h

    r8119363 rfbfe59d  
    3636#define LIBC_FUTEX_H_
    3737
    38 #include <assert.h>
    3938#include <atomic.h>
    4039#include <errno.h>
    4140#include <libc.h>
    42 #include <time.h>
    4341
    4442typedef struct futex {
    4543        atomic_t val;
    46 #ifdef CONFIG_DEBUG_FUTEX
    47         _Atomic void *owner;
     44#ifdef FUTEX_UPGRADABLE
     45        int upgraded;
    4846#endif
    4947} futex_t;
    5048
     49
    5150extern void futex_initialize(futex_t *futex, int value);
    5251
    53 #ifdef CONFIG_DEBUG_FUTEX
     52#ifdef FUTEX_UPGRADABLE
     53#include <rcu.h>
    5454
    55 #define FUTEX_INITIALIZE(val) {{ (val) }, NULL }
    56 #define FUTEX_INITIALIZER     FUTEX_INITIALIZE(1)
     55#define FUTEX_INITIALIZE(val) {{ (val) }, 0}
    5756
    58 void __futex_assert_is_locked(futex_t *, const char *);
    59 void __futex_assert_is_not_locked(futex_t *, const char *);
    60 void __futex_lock(futex_t *, const char *);
    61 void __futex_unlock(futex_t *, const char *);
    62 bool __futex_trylock(futex_t *, const char *);
    63 void __futex_give_to(futex_t *, void *, const char *);
     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})
    6464
    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)
     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})
    6882
    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)
     83#define futex_unlock(fut) \
     84({ \
     85        if ((fut)->upgraded) \
     86                (void) futex_up((fut)); \
     87        rcu_read_unlock(); \
     88})
     89
     90extern int _upgrade_futexes;
     91
     92extern void futex_upgrade_all_and_wait(void);
    7293
    7394#else
    7495
    7596#define FUTEX_INITIALIZE(val) {{ (val) }}
    76 #define FUTEX_INITIALIZER     FUTEX_INITIALIZE(1)
    7797
    7898#define futex_lock(fut)     (void) futex_down((fut))
     
    80100#define futex_unlock(fut)   (void) futex_up((fut))
    81101
    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)
     102#endif
    85103
    86 #endif
     104#define FUTEX_INITIALIZER     FUTEX_INITIALIZE(1)
    87105
    88106/** Try to down the futex.
     
    99117}
    100118
    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.
     119/** Down the futex.
    108120 *
    109121 * @param futex Futex.
    110122 *
    111123 * @return ENOENT if there is no such virtual address.
    112  * @return ETIMEOUT if timeout expires.
    113124 * @return EOK on success.
    114125 * @return Error code from <errno.h> otherwise.
    115126 *
    116127 */
    117 static inline errno_t futex_down_composable(futex_t *futex, struct timeval *expires)
     128static inline errno_t futex_down(futex_t *futex)
    118129{
    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 
    137130        if ((atomic_signed_t) atomic_predec(&futex->val) < 0)
    138                 return (errno_t) __SYSCALL2(SYS_FUTEX_SLEEP, (sysarg_t) &futex->val.count, (sysarg_t) timeout);
     131                return (errno_t) __SYSCALL1(SYS_FUTEX_SLEEP, (sysarg_t) &futex->val.count);
    139132
    140133        return EOK;
     
    158151}
    159152
    160 static 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  */
    182 static inline errno_t futex_down(futex_t *futex)
    183 {
    184         return futex_down_timeout(futex, NULL);
    185 }
    186 
    187153#endif
    188154
  • uspace/lib/c/include/rcu.h

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

    r8119363 rfbfe59d  
    4343typedef struct {
    4444        errno_t (*read_uintptr)(void *, uintptr_t, uintptr_t *);
    45         int (*printf)(const char *, ...);
    4645} stacktrace_ops_t;
    4746
     
    5251
    5352extern void stacktrace_print(void);
    54 extern void stacktrace_kio_print(void);
    5553extern void stacktrace_print_fp_pc(uintptr_t, uintptr_t);
    5654extern void stacktrace_print_generic(stacktrace_ops_t *, void *, uintptr_t,
  • uspace/lib/c/include/sys/time.h

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

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