Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/generic/async/server.c

    r3bd1d7d4 re768aea  
    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 */
Note: See TracChangeset for help on using the changeset viewer.