Changeset 43e2cbc in mainline


Ignore:
Timestamp:
2016-09-10T13:56:43Z (8 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
0b00599
Parents:
838ea8aa
Message:

Implement interruptible wait for messages sent by the kernel

This pertains specifically to handling the IPC_M_PAGE_IN requests
sent by the kernel on behalf of the faulting thread. If the external
pager process does not respond for some reason, the user may decide to
kill the blocked client. That will result in interrupting the client
from the sleep. The kernel will then perform cleanup.

This changeset implements the cleanup by either forgetting the call
(i.e. donating it to the callee) or waiting for the arriving answer,
whichever of the two succeeds.

Location:
kernel/generic/src/ipc
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/ipc/ipc.c

    r838ea8aa r43e2cbc  
    5959#include <ipc/irq.h>
    6060
     61static void ipc_forget_call(call_t *);
     62
    6163/** Open channel that is assigned automatically to new tasks */
    6264answerbox_t *ipc_phone_0 = NULL;
     
    209211                return rc;
    210212        }
    211         // TODO: forget the call if interrupted
    212         (void) ipc_wait_for_call(mybox, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE);
     213
     214        call_t *answer = ipc_wait_for_call(mybox, SYNCH_NO_TIMEOUT,
     215            SYNCH_FLAGS_INTERRUPTIBLE);
     216        if (!answer) {
     217
     218                /*
     219                 * The sleep was interrupted.
     220                 *
     221                 * There are two possibilities now:
     222                 * 1) the call gets answered before we manage to forget it
     223                 * 2) we manage to forget the call before it gets answered
     224                 */
     225
     226                spinlock_lock(&request->forget_lock);
     227                spinlock_lock(&TASK->active_calls_lock);
     228
     229                ASSERT(!request->forget);
     230
     231                bool answered = !request->active;
     232                if (!answered) {
     233                        /*
     234                         * The call is not yet answered and we won the race to
     235                         * forget it.
     236                         */
     237                        ipc_forget_call(request);       /* releases locks */
     238                        rc = EINTR;
     239                       
     240                } else {
     241                        spinlock_unlock(&TASK->active_calls_lock);
     242                        spinlock_unlock(&request->forget_lock);
     243                }
     244
     245                if (answered) {
     246                        /*
     247                         * The other side won the race to answer the call.
     248                         * It is safe to wait for the answer uninterruptibly
     249                         * now.
     250                         */
     251                        answer = ipc_wait_for_call(mybox, SYNCH_NO_TIMEOUT,
     252                            SYNCH_FLAGS_NONE);
     253                }
     254        }
     255        ASSERT(!answer || request == answer);
    213256       
    214257        slab_free(ipc_answerbox_slab, mybox);
    215         return EOK;
     258        return rc;
    216259}
    217260
     
    621664}
    622665
     666static void ipc_forget_call(call_t *call)
     667{
     668        ASSERT(spinlock_locked(&TASK->active_calls_lock));
     669        ASSERT(spinlock_locked(&call->forget_lock));
     670
     671        /*
     672         * Forget the call and donate it to the task which holds up the answer.
     673         */
     674
     675        call->forget = true;
     676        call->sender = NULL;
     677        list_remove(&call->ta_link);
     678
     679        /*
     680         * The call may be freed by _ipc_answer_free_call() before we are done
     681         * with it; to avoid working with a destroyed call_t structure, we
     682         * must hold a reference to it.
     683         */
     684        ipc_call_hold(call);
     685
     686        spinlock_unlock(&call->forget_lock);
     687        spinlock_unlock(&TASK->active_calls_lock);
     688
     689        atomic_dec(&call->caller_phone->active_calls);
     690
     691        SYSIPC_OP(request_forget, call);
     692
     693        ipc_call_release(call);
     694}
     695
    623696static void ipc_forget_all_active_calls(void)
    624697{
     
    649722        }
    650723
    651         /*
    652          * Forget the call and donate it to the task which holds up the answer.
    653          */
    654 
    655         call->forget = true;
    656         call->sender = NULL;
    657         list_remove(&call->ta_link);
    658 
    659         /*
    660          * The call may be freed by _ipc_answer_free_call() before we are done
    661          * with it; to avoid working with a destroyed call_t structure, we
    662          * must hold a reference to it.
    663          */
    664         ipc_call_hold(call);
    665 
    666         spinlock_unlock(&call->forget_lock);
    667         spinlock_unlock(&TASK->active_calls_lock);
    668 
    669         atomic_dec(&call->caller_phone->active_calls);
    670 
    671         SYSIPC_OP(request_forget, call);
    672 
    673         ipc_call_release(call);
     724        ipc_forget_call(call);
    674725
    675726        goto restart;
  • kernel/generic/src/ipc/sysipc.c

    r838ea8aa r43e2cbc  
    285285#endif
    286286
    287                 rc = ipc_call_sync(phone, call);
     287                ipc_call_hold(call);
     288                rc = ipc_call_sync(phone, call);
     289                spinlock_lock(&call->forget_lock);
     290                bool forgotten = call->forget;
     291                spinlock_unlock(&call->forget_lock);
     292                ipc_call_release(call);
    288293
    289294#ifdef CONFIG_UDEBUG
     
    291296#endif
    292297
    293                 if (rc != EOK)
    294                         return EINTR;
     298                if (rc != EOK) {
     299                        if (!forgotten) {
     300                                /*
     301                                 * There was an error, but it did not result
     302                                 * in the call being forgotten. In fact, the
     303                                 * call was not even sent. We are still
     304                                 * its owners and are responsible for its
     305                                 * deallocation.
     306                                 */
     307                                ipc_call_free(call);
     308                        } else {
     309                                /*
     310                                 * The call was forgotten and it changed hands.
     311                                 * We are no longer expected to free it.
     312                                 */
     313                                ASSERT(rc == EINTR);
     314                        }
     315                        return rc;     
     316                }
    295317
    296318                process_answer(call);
Note: See TracChangeset for help on using the changeset viewer.