Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset 1db6dfd in mainline


Ignore:
Timestamp:
2012-04-14T08:12:35Z (10 years ago)
Author:
Vojtech Horky <vojtechhorky@…>
Branches:
lfn, master
Children:
831507b, f76696f
Parents:
3191c01
Message:

Fix starving IPC problem

Check for incoming IPC regardless of expired timeouts.

File:
1 edited

Legend:

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

    r3191c01 r1db6dfd  
    10171017               
    10181018                suseconds_t timeout;
     1019                unsigned int flags = SYNCH_FLAGS_NONE;
    10191020                if (!list_empty(&timeout_list)) {
    10201021                        awaiter_t *waiter = list_get_instance(
     
    10271028                                futex_up(&async_futex);
    10281029                                handle_expired_timeouts();
    1029                                 continue;
    1030                         } else
     1030                                /*
     1031                                 * Notice that even if the event(s) already
     1032                                 * expired (and thus the other fibril was
     1033                                 * supposed to be running already),
     1034                                 * we check for incoming IPC.
     1035                                 *
     1036                                 * Otherwise, a fibril that continuously
     1037                                 * creates (almost) expired events could
     1038                                 * prevent IPC retrieval from the kernel.
     1039                                 */
     1040                                timeout = 0;
     1041                                flags = SYNCH_FLAGS_NON_BLOCKING;
     1042
     1043                        } else {
    10311044                                timeout = tv_sub(&waiter->to_event.expires, &tv);
    1032                 } else
     1045                                futex_up(&async_futex);
     1046                        }
     1047                } else {
     1048                        futex_up(&async_futex);
    10331049                        timeout = SYNCH_NO_TIMEOUT;
    1034                
    1035                 futex_up(&async_futex);
     1050                }
    10361051               
    10371052                atomic_inc(&threads_in_ipc_wait);
    10381053               
    10391054                ipc_call_t call;
    1040                 ipc_callid_t callid = ipc_wait_cycle(&call, timeout,
    1041                     SYNCH_FLAGS_NONE);
     1055                ipc_callid_t callid = ipc_wait_cycle(&call, timeout, flags);
    10421056               
    10431057                atomic_dec(&threads_in_ipc_wait);
     
    12981312       
    12991313        amsg_t *msg = (amsg_t *) amsgid;
    1300        
    1301         /* TODO: Let it go through the event read at least once */
    1302         if (timeout < 0)
    1303                 return ETIMEOUT;
    1304        
     1314
    13051315        futex_down(&async_futex);
    13061316
     
    13131323        }
    13141324       
     1325        /*
     1326         * Negative timeout is converted to zero timeout to avoid
     1327         * using tv_add with negative augmenter.
     1328         */
     1329        if (timeout < 0)
     1330                timeout = 0;
     1331
    13151332        gettimeofday(&msg->wdata.to_event.expires, NULL);
    13161333        tv_add(&msg->wdata.to_event.expires, timeout);
    13171334       
     1335        /*
     1336         * Current fibril is inserted as waiting regardless of the
     1337         * "size" of the timeout.
     1338         *
     1339         * Checking for msg->done and immediately bailing out when
     1340         * timeout == 0 would mean that the manager fibril would never
     1341         * run (consider single threaded program).
     1342         * Thus the IPC answer would be never retrieved from the kernel.
     1343         *
     1344         * Notice that the actual delay would be very small because we
     1345         * - switch to manager fibril
     1346         * - the manager sees expired timeout
     1347         * - and thus adds us back to ready queue
     1348         * - manager switches back to some ready fibril
     1349         *   (prior it, it checks for incoming IPC).
     1350         *
     1351         */
    13181352        msg->wdata.fid = fibril_get_id();
    13191353        msg->wdata.active = false;
Note: See TracChangeset for help on using the changeset viewer.