Changeset c170438 in mainline


Ignore:
Timestamp:
2016-05-24T21:00:37Z (8 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
2a7ba5e
Parents:
f570cdf
Message:

Do not create a new fibril for each IRQ notification

In the absence of fibril serialization, manager fibrils can
theoretically block in async IPC or on fibril synchronization
primitives. Consequently, it is safe to execute the IRQ handler directly
from the manager fibril. The manager fibril can block while processing
the notification, but most of the times it will not block and the
handler will execute atomically.

This changeset modifies the current behaviour so that we no longer spawn
a new notification fibril for each IRQ, but rather execute the handler
directly from the manager fibril and test if the execution blocked. If
it blocked, the manager fibril had assumed the role of a notification
fibril and we destroy it afterwards - merely to avoid fibril population
explosion. Otherwise, which is the usual behavior, we keep it so that
it resumes its job of a manager fibril.

Location:
uspace
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/char/i8042/main.c

    rf570cdf rc170438  
    4343#include <ddf/log.h>
    4444#include <stdio.h>
    45 #include <async.h>
    4645#include "i8042.h"
    4746
     
    152151        ddf_log_init(NAME);
    153152       
    154         /*
    155          * Alleviate the virtual memory / page table pressure caused by
    156          * interrupt storms when the default large stacks are used.
    157          */
    158         async_set_notification_handler_stack_size(PAGE_SIZE);
    159 
    160153        return ddf_driver_main(&i8042_driver);
    161154}
  • uspace/lib/c/generic/async.c

    rf570cdf rc170438  
    493493}
    494494
    495 static size_t notification_handler_stksz = FIBRIL_DFLT_STK_SIZE;
    496 
    497 /** Set the stack size for the notification handler notification fibrils.
    498  *
    499  * @param size Stack size in bytes.
    500  */
    501 void async_set_notification_handler_stack_size(size_t size)
    502 {
    503         notification_handler_stksz = size;
    504 }
    505 
    506495/** Mutex protecting inactive_exch_list and avail_phone_cv.
    507496 *
     
    998987}
    999988
    1000 /** Notification fibril.
    1001  *
    1002  * When a notification arrives, a fibril with this implementing function is
    1003  * created. It calls the corresponding notification handler and does the final
    1004  * cleanup.
    1005  *
    1006  * @param arg Message structure pointer.
    1007  *
    1008  * @return Always zero.
    1009  *
    1010  */
    1011 static int notification_fibril(void *arg)
    1012 {
    1013         assert(arg);
    1014        
    1015         msg_t *msg = (msg_t *) arg;
     989/** Process notification.
     990 *
     991 * @param callid Hash of the incoming call.
     992 * @param call   Data of the incoming call.
     993 */
     994static void process_notification(ipc_callid_t callid, ipc_call_t *call)
     995{
    1016996        async_notification_handler_t handler = NULL;
    1017997        void *data = NULL;
     998
     999        assert(call);
    10181000       
    10191001        futex_down(&async_futex);
    10201002       
    10211003        ht_link_t *link = hash_table_find(&notification_hash_table,
    1022             &IPC_GET_IMETHOD(msg->call));
     1004            &IPC_GET_IMETHOD(*call));
    10231005        if (link) {
    10241006                notification_t *notification =
     
    10311013       
    10321014        if (handler)
    1033                 handler(msg->callid, &msg->call, data);
    1034        
    1035         free(msg);
    1036         return 0;
    1037 }
    1038 
    1039 /** Process notification.
    1040  *
    1041  * A new fibril is created which would process the notification.
    1042  *
    1043  * @param callid Hash of the incoming call.
    1044  * @param call   Data of the incoming call.
    1045  *
    1046  * @return False if an error occured.
    1047  *         True if the call was passed to the notification fibril.
    1048  *
    1049  */
    1050 static bool process_notification(ipc_callid_t callid, ipc_call_t *call)
    1051 {
    1052         assert(call);
    1053        
    1054         futex_down(&async_futex);
    1055        
    1056         msg_t *msg = malloc(sizeof(*msg));
    1057         if (!msg) {
    1058                 futex_up(&async_futex);
    1059                 return false;
    1060         }
    1061        
    1062         msg->callid = callid;
    1063         msg->call = *call;
    1064        
    1065         fid_t fid = fibril_create_generic(notification_fibril, msg,
    1066             notification_handler_stksz);
    1067         if (fid == 0) {
    1068                 free(msg);
    1069                 futex_up(&async_futex);
    1070                 return false;
    1071         }
    1072        
    1073         fibril_add_ready(fid);
    1074        
    1075         futex_up(&async_futex);
    1076         return true;
     1015                handler(callid, call, data);
    10771016}
    10781017
     
    13751314        /* Kernel notification */
    13761315        if ((callid & IPC_CALLID_NOTIFICATION)) {
     1316                fibril_t *fibril = (fibril_t *) __tcb_get()->fibril_data;
     1317                unsigned oldsw = fibril->switches;
     1318
    13771319                process_notification(callid, call);
     1320
     1321                if (oldsw != fibril->switches) {
     1322                        /*
     1323                         * The notification handler did not execute atomically
     1324                         * and so the current manager fibril assumed the role of
     1325                         * a notification fibril. While waiting for its
     1326                         * resources, it switched to another manager fibril that
     1327                         * had already existed or it created a new one. We
     1328                         * therefore know there is at least yet another
     1329                         * manager fibril that can take over. We now kill the
     1330                         * current 'notification' fibril to prevent fibril
     1331                         * population explosion.
     1332                         */
     1333                        futex_down(&async_futex);
     1334                        fibril_switch(FIBRIL_FROM_DEAD);
     1335                }
    13781336                return;
    13791337        }
     
    15501508void async_create_manager(void)
    15511509{
    1552         fid_t fid = fibril_create(async_manager_fibril, NULL);
     1510        fid_t fid = fibril_create_generic(async_manager_fibril, NULL, PAGE_SIZE);
    15531511        if (fid != 0)
    15541512                fibril_add_manager(fid);
  • uspace/lib/c/generic/fibril.c

    rf570cdf rc170438  
    113113       
    114114        fibril->waits_for = NULL;
     115
     116        fibril->switches = 0;
    115117
    116118        /*
     
    216218                        assert(stype == FIBRIL_TO_MANAGER);
    217219
     220                        srcf->switches++;
     221
    218222                        /*
    219223                         * Don't put the current fibril into any list, it should
  • uspace/lib/c/generic/ipc.c

    rf570cdf rc170438  
    9696}
    9797
    98 /** Prolog for ipc_call_async_*() functions.
     98/** Prologue for ipc_call_async_*() functions.
    9999 *
    100100 * @param private  Argument for the answer/error callback.
     
    122122}
    123123
    124 /** Epilog for ipc_call_async_*() functions.
     124/** Epilogue for ipc_call_async_*() functions.
    125125 *
    126126 * @param callid      Value returned by the SYS_IPC_CALL_ASYNC_* syscall.
  • uspace/lib/c/include/async.h

    rf570cdf rc170438  
    165165extern int async_create_callback_port(async_exch_t *, iface_t, sysarg_t,
    166166    sysarg_t, async_port_handler_t, void *, port_id_t *);
    167 
    168 extern void async_set_notification_handler_stack_size(size_t);
    169167
    170168extern int async_irq_subscribe(int, int, async_notification_handler_t, void *,
  • uspace/lib/c/include/fibril.h

    rf570cdf rc170438  
    7878       
    7979        fibril_owner_info_t *waits_for;
     80
     81        unsigned switches;
    8082} fibril_t;
    8183
  • uspace/srv/hw/bus/cuda_adb/cuda_adb.c

    rf570cdf rc170438  
    4747#include <errno.h>
    4848#include <ipc/adb.h>
    49 #include <async.h>
    5049#include <assert.h>
    5150#include "cuda_adb.h"
     
    158157        printf(NAME ": VIA-CUDA Apple Desktop Bus driver\n");
    159158       
    160         /*
    161          * Alleviate the virtual memory / page table pressure caused by
    162          * interrupt storms when the default large stacks are used.
    163          */
    164         async_set_notification_handler_stack_size(PAGE_SIZE);
    165 
    166159        for (i = 0; i < ADB_MAX_ADDR; ++i) {
    167160                adb_dev[i].client_sess = NULL;
Note: See TracChangeset for help on using the changeset viewer.