Changeset 00b4a68 in mainline


Ignore:
Timestamp:
2012-09-15T21:41:51Z (12 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
ccc3debf, fedac2f
Parents:
40b5421 (diff), e9fe33b (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge from lp:~jakub/helenos/camp2012.

Kernel IPC subsystem improvements and fixes.

  • call forgetting
  • call processing callbacks
  • fixes of IPC_M_CONNECT_ME/TO_TO/ME handling in IPC cleanup
  • fix of EHANGUP processing
  • reliable call sender identification
Files:
13 added
13 edited

Legend:

Unmodified
Added
Removed
  • abi/include/ipc/ipc.h

    r40b5421 r00b4a68  
    5757#define IPC_CALL_FORWARDED  (1 << 2)
    5858
    59 /** Identify connect_me_to answer */
    60 #define IPC_CALL_CONN_ME_TO  (1 << 3)
    61 
    6259/** Interrupt notification */
    63 #define IPC_CALL_NOTIF  (1 << 4)
     60#define IPC_CALL_NOTIF  (1 << 3)
    6461
    6562
  • kernel/Makefile

    r40b5421 r00b4a68  
    257257        generic/src/ipc/ipc.c \
    258258        generic/src/ipc/sysipc.c \
     259        generic/src/ipc/sysipc_ops.c \
     260        generic/src/ipc/ops/clnestab.c \
     261        generic/src/ipc/ops/conctmeto.c \
     262        generic/src/ipc/ops/concttome.c \
     263        generic/src/ipc/ops/connclone.c \
     264        generic/src/ipc/ops/dataread.c \
     265        generic/src/ipc/ops/datawrite.c \
     266        generic/src/ipc/ops/debug.c \
     267        generic/src/ipc/ops/sharein.c \
     268        generic/src/ipc/ops/shareout.c \
     269        generic/src/ipc/ops/stchngath.c \
    259270        generic/src/ipc/ipcrsc.c \
    260271        generic/src/ipc/irq.c \
  • kernel/generic/include/config.h

    r40b5421 r00b4a68  
    4848#define CONFIG_TASK_NAME_BUFLEN  32
    4949#define CONFIG_TASK_ARGUMENTS_BUFLEN 64
     50
     51/**
     52 * Maximum buffer size allowed for IPC_M_DATA_WRITE and IPC_M_DATA_READ
     53 * requests.
     54 */
     55#define DATA_XFER_LIMIT  (64 * 1024)
    5056
    5157#ifndef __ASM__
  • kernel/generic/include/ipc/ipc.h

    r40b5421 r00b4a68  
    6565        mutex_t lock;
    6666        link_t link;
     67        struct task *caller;
    6768        struct answerbox *callee;
    6869        ipc_phone_state_t state;
     
    7273typedef struct answerbox {
    7374        IRQ_SPINLOCK_DECLARE(lock);
     75
     76        /** Answerbox is active until it enters cleanup. */
     77        bool active;
    7478       
    7579        struct task *task;
     
    106110
    107111typedef struct {
    108         link_t link;
     112        /**
     113         * Task link.
     114         * Valid only when the call is not forgotten.
     115         * Protected by the task's active_calls_lock.
     116         */
     117        link_t ta_link;
     118
     119        atomic_t refcnt;
     120
     121        /** Answerbox link. */
     122        link_t ab_link;
    109123       
    110124        unsigned int flags;
     125
     126        /** Protects the forget member. */
     127        SPINLOCK_DECLARE(forget_lock);
     128
     129        /**
     130         * True if the caller 'forgot' this call and donated it to the callee.
     131         * Forgotten calls are discarded upon answering (the answer is not
     132         * delivered) and answered calls cannot be forgotten. Forgotten calls
     133         * also do not figure on the task's active call list.
     134         *
     135         * We keep this separate from the flags so that it is not necessary
     136         * to take a lock when accessing them.
     137         */
     138        bool forget;
     139
     140        /** True if the call is in the active list. */
     141        bool active;
    111142       
    112         /** Identification of the caller. */
     143        /**
     144         * Identification of the caller.
     145         * Valid only when the call is not forgotten.
     146         */
    113147        struct task *sender;
     148       
     149        /** Phone which was used to send the call. */
     150        phone_t *caller_phone;
    114151       
    115152        /** Private data to internal IPC. */
     
    118155        /** Data passed from/to userspace. */
    119156        ipc_data_t data;
    120        
     157
     158        /** Method as it was sent in the request. */
     159        sysarg_t request_method;
     160
    121161        /** Buffer for IPC_M_DATA_WRITE and IPC_M_DATA_READ. */
    122162        uint8_t *buffer;
    123        
    124         /*
    125          * The forward operation can masquerade the caller phone. For those
    126          * cases, we must keep it aside so that the answer is processed
    127          * correctly.
    128          */
    129         phone_t *caller_phone;
    130163} call_t;
    131164
     
    136169extern call_t *ipc_call_alloc(unsigned int);
    137170extern void ipc_call_free(call_t *);
     171extern void ipc_call_hold(call_t *);
     172extern void ipc_call_release(call_t *);
    138173
    139174extern int ipc_call(phone_t *, call_t *);
     
    141176extern int ipc_forward(call_t *, phone_t *, answerbox_t *, unsigned int);
    142177extern void ipc_answer(answerbox_t *, call_t *);
     178extern void _ipc_answer_free_call(call_t *, bool);
    143179
    144 extern void ipc_phone_init(phone_t *);
    145 extern void ipc_phone_connect(phone_t *, answerbox_t *);
     180extern void ipc_phone_init(phone_t *, struct task *);
     181extern bool ipc_phone_connect(phone_t *, answerbox_t *);
    146182extern int ipc_phone_hangup(phone_t *);
    147183
     
    151187extern void ipc_backsend_err(phone_t *, call_t *, sysarg_t);
    152188extern void ipc_answerbox_slam_phones(answerbox_t *, bool);
    153 extern void ipc_cleanup_call_list(list_t *);
     189extern void ipc_cleanup_call_list(answerbox_t *, list_t *);
    154190
    155191extern void ipc_print_task(task_id_t);
  • kernel/generic/include/ipc/ipcrsc.h

    r40b5421 r00b4a68  
    4040
    4141extern call_t *get_call(sysarg_t);
     42extern int phone_get(sysarg_t, phone_t **);
    4243extern int phone_alloc(task_t *);
    43 extern void phone_connect(int, answerbox_t *);
     44extern bool phone_connect(int, answerbox_t *);
    4445extern void phone_dealloc(int);
    4546
  • kernel/generic/include/proc/task.h

    r40b5421 r00b4a68  
    9191       
    9292        /* IPC stuff */
    93         answerbox_t answerbox;  /**< Communication endpoint */
     93
     94        /** Receiving communication endpoint */
     95        answerbox_t answerbox;
     96
     97        /** Sending communication endpoints */
    9498        phone_t phones[IPC_MAX_PHONES];
    95         stats_ipc_t ipc_info;   /**< IPC statistics */
     99
     100        /** Spinlock protecting the active_calls list. */
     101        SPINLOCK_DECLARE(active_calls_lock);
     102
     103        /**
     104         * List of all calls sent by this task that have not yet been
     105         * answered.
     106         */
     107        list_t active_calls;
     108
    96109        event_t events[EVENT_TASK_END - EVENT_END];
     110
     111        /** IPC statistics */
     112        stats_ipc_t ipc_info;
    97113       
    98114#ifdef CONFIG_UDEBUG
  • kernel/generic/src/ipc/event.c

    r40b5421 r00b4a68  
    163163                                call->data.task_id = TASK ? TASK->taskid : 0;
    164164                               
    165                                 irq_spinlock_lock(&event->answerbox->irq_lock, true);
    166                                 list_append(&call->link, &event->answerbox->irq_notifs);
    167                                 irq_spinlock_unlock(&event->answerbox->irq_lock, true);
    168                                
    169                                 waitq_wakeup(&event->answerbox->wq, WAKEUP_FIRST);
     165                                irq_spinlock_lock(&event->answerbox->irq_lock,
     166                                    true);
     167                                list_append(&call->ab_link,
     168                                    &event->answerbox->irq_notifs);
     169                                irq_spinlock_unlock(&event->answerbox->irq_lock,
     170                                    true);
     171                               
     172                                waitq_wakeup(&event->answerbox->wq,
     173                                    WAKEUP_FIRST);
    170174                               
    171175                                if (mask)
  • kernel/generic/src/ipc/ipc.c

    r40b5421 r00b4a68  
    4545#include <ipc/kbox.h>
    4646#include <ipc/event.h>
     47#include <ipc/sysipc_ops.h>
     48#include <ipc/sysipc_priv.h>
    4749#include <errno.h>
    4850#include <mm/slab.h>
     
    7173{
    7274        memsetb(call, sizeof(*call), 0);
    73         call->sender = TASK;
     75        spinlock_initialize(&call->forget_lock, "forget_lock");
     76        call->active = false;
     77        call->forget = false;
     78        call->sender = NULL;
    7479        call->buffer = NULL;
     80}
     81
     82void ipc_call_hold(call_t *call)
     83{
     84        atomic_inc(&call->refcnt);
     85}
     86
     87void ipc_call_release(call_t *call)
     88{
     89        if (atomic_predec(&call->refcnt) == 0) {
     90                if (call->buffer)
     91                        free(call->buffer);
     92                slab_free(ipc_call_slab, call);
     93        }
    7594}
    7695
     
    83102 *
    84103 * @return If flags permit it, return NULL, or initialized kernel
    85  *         call structure.
     104 *         call structure with one reference.
    86105 *
    87106 */
     
    89108{
    90109        call_t *call = slab_alloc(ipc_call_slab, flags);
    91         if (call)
     110        if (call) {
    92111                _ipc_call_init(call);
     112                ipc_call_hold(call);
     113        }
    93114       
    94115        return call;
     
    102123void ipc_call_free(call_t *call)
    103124{
    104         /* Check to see if we have data in the IPC_M_DATA_SEND buffer. */
    105         if (call->buffer)
    106                 free(call->buffer);
    107         slab_free(ipc_call_slab, call);
     125        ipc_call_release(call);
    108126}
    109127
     
    132150 * @param phone Initialized phone structure.
    133151 * @param box   Initialized answerbox structure.
    134  *
    135  */
    136 void ipc_phone_connect(phone_t *phone, answerbox_t *box)
    137 {
     152 * @return      True if the phone was connected, false otherwise.
     153 */
     154bool ipc_phone_connect(phone_t *phone, answerbox_t *box)
     155{
     156        bool active;
     157
    138158        mutex_lock(&phone->lock);
    139        
    140         phone->state = IPC_PHONE_CONNECTED;
    141         phone->callee = box;
    142        
    143159        irq_spinlock_lock(&box->lock, true);
    144         list_append(&phone->link, &box->connected_phones);
     160
     161        active = box->active;
     162        if (active) {
     163                phone->state = IPC_PHONE_CONNECTED;
     164                phone->callee = box;
     165                list_append(&phone->link, &box->connected_phones);
     166        }
     167
    145168        irq_spinlock_unlock(&box->lock, true);
    146        
    147169        mutex_unlock(&phone->lock);
     170
     171        return active;
    148172}
    149173
     
    151175 *
    152176 * @param phone Phone structure to be initialized.
    153  *
    154  */
    155 void ipc_phone_init(phone_t *phone)
     177 * @param caller Owning task.
     178 *
     179 */
     180void ipc_phone_init(phone_t *phone, task_t *caller)
    156181{
    157182        mutex_initialize(&phone->lock, MUTEX_PASSIVE);
     183        phone->caller = caller;
    158184        phone->callee = NULL;
    159185        phone->state = IPC_PHONE_FREE;
     
    167193 *
    168194 */
    169 static void _ipc_answer_free_call(call_t *call, bool selflocked)
    170 {
    171         answerbox_t *callerbox = &call->sender->answerbox;
    172         bool do_lock = ((!selflocked) || callerbox != (&TASK->answerbox));
    173        
     195void _ipc_answer_free_call(call_t *call, bool selflocked)
     196{
    174197        /* Count sent answer */
    175198        irq_spinlock_lock(&TASK->lock, true);
    176199        TASK->ipc_info.answer_sent++;
    177200        irq_spinlock_unlock(&TASK->lock, true);
     201
     202        spinlock_lock(&call->forget_lock);
     203        if (call->forget) {
     204                /* This is a forgotten call and call->sender is not valid. */
     205                spinlock_unlock(&call->forget_lock);
     206                ipc_call_free(call);
     207                return;
     208        } else {
     209                /*
     210                 * If the call is still active, i.e. it was answered
     211                 * in a non-standard way, remove the call from the
     212                 * sender's active call list.
     213                 */
     214                if (call->active) {
     215                        spinlock_lock(&call->sender->active_calls_lock);
     216                        list_remove(&call->ta_link);
     217                        spinlock_unlock(&call->sender->active_calls_lock);
     218                }
     219        }
     220        spinlock_unlock(&call->forget_lock);
     221
     222        answerbox_t *callerbox = &call->sender->answerbox;
     223        bool do_lock = ((!selflocked) || (callerbox != &TASK->answerbox));
    178224       
    179225        call->flags |= IPC_CALL_ANSWERED;
    180226       
    181         if (call->flags & IPC_CALL_FORWARDED) {
    182                 if (call->caller_phone) {
    183                         /* Demasquerade the caller phone. */
    184                         call->data.phone = call->caller_phone;
    185                 }
    186         }
    187 
    188227        call->data.task_id = TASK->taskid;
    189228       
     
    191230                irq_spinlock_lock(&callerbox->lock, true);
    192231       
    193         list_append(&call->link, &callerbox->answers);
     232        list_append(&call->ab_link, &callerbox->answers);
    194233       
    195234        if (do_lock)
     
    209248        /* Remove from active box */
    210249        irq_spinlock_lock(&box->lock, true);
    211         list_remove(&call->link);
     250        list_remove(&call->ab_link);
    212251        irq_spinlock_unlock(&box->lock, true);
    213252       
     
    228267void ipc_backsend_err(phone_t *phone, call_t *call, sysarg_t err)
    229268{
     269        task_t *caller = phone->caller;
     270
     271        atomic_inc(&phone->active_calls);
     272        call->caller_phone = phone;
     273        call->sender = caller;
     274
     275        call->active = true;
     276        spinlock_lock(&caller->active_calls_lock);
     277        list_append(&call->ta_link, &caller->active_calls);
     278        spinlock_unlock(&caller->active_calls_lock);
     279
    230280        call->data.phone = phone;
    231         atomic_inc(&phone->active_calls);
     281
    232282        IPC_SET_RETVAL(call->data, err);
    233283        _ipc_answer_free_call(call, false);
     
    243293static void _ipc_call(phone_t *phone, answerbox_t *box, call_t *call)
    244294{
     295        task_t *caller = phone->caller;
     296
    245297        /* Count sent ipc call */
    246         irq_spinlock_lock(&TASK->lock, true);
    247         TASK->ipc_info.call_sent++;
    248         irq_spinlock_unlock(&TASK->lock, true);
     298        irq_spinlock_lock(&caller->lock, true);
     299        caller->ipc_info.call_sent++;
     300        irq_spinlock_unlock(&caller->lock, true);
    249301       
    250302        if (!(call->flags & IPC_CALL_FORWARDED)) {
    251303                atomic_inc(&phone->active_calls);
     304                call->caller_phone = phone;
     305                call->sender = caller;
     306
     307                call->active = true;
     308                spinlock_lock(&caller->active_calls_lock);
     309                list_append(&call->ta_link, &caller->active_calls);
     310                spinlock_unlock(&caller->active_calls_lock);
     311
    252312                call->data.phone = phone;
    253                 call->data.task_id = TASK->taskid;
     313                call->data.task_id = caller->taskid;
    254314        }
    255315       
    256316        irq_spinlock_lock(&box->lock, true);
    257         list_append(&call->link, &box->calls);
     317        list_append(&call->ab_link, &box->calls);
    258318        irq_spinlock_unlock(&box->lock, true);
    259319       
     
    275335        if (phone->state != IPC_PHONE_CONNECTED) {
    276336                mutex_unlock(&phone->lock);
    277                 if (call->flags & IPC_CALL_FORWARDED) {
    278                         IPC_SET_RETVAL(call->data, EFORWARD);
    279                         _ipc_answer_free_call(call, false);
    280                 } else {
     337                if (!(call->flags & IPC_CALL_FORWARDED)) {
    281338                        if (phone->state == IPC_PHONE_HUNGUP)
    282339                                ipc_backsend_err(phone, call, EHANGUP);
     
    325382                call_t *call = ipc_call_alloc(0);
    326383                IPC_SET_IMETHOD(call->data, IPC_M_PHONE_HUNGUP);
     384                call->request_method = IPC_M_PHONE_HUNGUP;
    327385                call->flags |= IPC_CALL_DISCARD_ANSWER;
    328386                _ipc_call(phone, box, call);
     
    356414        TASK->ipc_info.forwarded++;
    357415        irq_spinlock_pass(&TASK->lock, &oldbox->lock);
    358         list_remove(&call->link);
     416        list_remove(&call->ab_link);
    359417        irq_spinlock_unlock(&oldbox->lock, true);
    360418       
    361419        if (mode & IPC_FF_ROUTE_FROM_ME) {
    362                 if (!call->caller_phone)
    363                         call->caller_phone = call->data.phone;
    364420                call->data.phone = newphone;
    365421                call->data.task_id = TASK->taskid;
     
    406462               
    407463                request = list_get_instance(list_first(&box->irq_notifs),
    408                     call_t, link);
    409                 list_remove(&request->link);
     464                    call_t, ab_link);
     465                list_remove(&request->ab_link);
    410466               
    411467                irq_spinlock_unlock(&box->irq_lock, false);
     
    416472                /* Handle asynchronous answers */
    417473                request = list_get_instance(list_first(&box->answers),
    418                     call_t, link);
    419                 list_remove(&request->link);
    420                 atomic_dec(&request->data.phone->active_calls);
     474                    call_t, ab_link);
     475                list_remove(&request->ab_link);
     476                atomic_dec(&request->caller_phone->active_calls);
    421477        } else if (!list_empty(&box->calls)) {
    422478                /* Count received call */
     
    425481                /* Handle requests */
    426482                request = list_get_instance(list_first(&box->calls),
    427                     call_t, link);
    428                 list_remove(&request->link);
     483                    call_t, ab_link);
     484                list_remove(&request->ab_link);
    429485               
    430486                /* Append request to dispatch queue */
    431                 list_append(&request->link, &box->dispatched_calls);
     487                list_append(&request->ab_link, &box->dispatched_calls);
    432488        } else {
    433489                /* This can happen regularly after ipc_cleanup */
     
    449505/** Answer all calls from list with EHANGUP answer.
    450506 *
     507 * @param box Answerbox with the list.
    451508 * @param lst Head of the list to be cleaned up.
    452  *
    453  */
    454 void ipc_cleanup_call_list(list_t *lst)
    455 {
     509 */
     510void ipc_cleanup_call_list(answerbox_t *box, list_t *lst)
     511{
     512        irq_spinlock_lock(&box->lock, true);
    456513        while (!list_empty(lst)) {
    457                 call_t *call = list_get_instance(list_first(lst), call_t, link);
    458                 if (call->buffer)
    459                         free(call->buffer);
    460                
    461                 list_remove(&call->link);
    462                
     514                call_t *call = list_get_instance(list_first(lst), call_t,
     515                    ab_link);
     516               
     517                list_remove(&call->ab_link);
     518
     519                irq_spinlock_unlock(&box->lock, true);
     520
     521                ipc_data_t old = call->data;
    463522                IPC_SET_RETVAL(call->data, EHANGUP);
     523                answer_preprocess(call, &old);
    464524                _ipc_answer_free_call(call, true);
    465         }
     525
     526                irq_spinlock_lock(&box->lock, true);
     527        }
     528        irq_spinlock_unlock(&box->lock, true);
    466529}
    467530
     
    501564                        mutex_unlock(&phone->lock);
    502565                        irq_spinlock_unlock(&box->lock, true);
    503                        
     566
     567                        // FIXME: phone can become deallocated at any time now
     568
    504569                        /*
    505570                         * Send one message to the answerbox for each
     
    509574                         */
    510575                        IPC_SET_IMETHOD(call->data, IPC_M_PHONE_HUNGUP);
     576                        call->request_method = IPC_M_PHONE_HUNGUP;
    511577                        call->flags |= IPC_CALL_DISCARD_ANSWER;
    512578                        _ipc_call(phone, box, call);
     
    529595}
    530596
     597static void ipc_forget_all_active_calls(void)
     598{
     599        call_t *call;
     600
     601restart:
     602        spinlock_lock(&TASK->active_calls_lock);
     603        if (list_empty(&TASK->active_calls)) {
     604                /*
     605                 * We are done, there are no more active calls.
     606                 * Nota bene: there may still be answers waiting for pick up.
     607                 */
     608                spinlock_unlock(&TASK->active_calls_lock);     
     609                return;
     610        }
     611       
     612        call = list_get_instance(list_first(&TASK->active_calls), call_t,
     613            ta_link);
     614
     615        if (!spinlock_trylock(&call->forget_lock)) {
     616                /*
     617                 * Avoid deadlock and let async_answer() or
     618                 *  _ipc_answer_free_call() win the race to dequeue the first
     619                 * call on the list.
     620                 */
     621                spinlock_unlock(&TASK->active_calls_lock);     
     622                goto restart;
     623        }
     624
     625        /*
     626         * Forget the call and donate it to the task which holds up the answer.
     627         */
     628
     629        call->forget = true;
     630        call->sender = NULL;
     631        list_remove(&call->ta_link);
     632
     633        /*
     634         * The call may be freed by _ipc_answer_free_call() before we are done
     635         * with it; to avoid working with a destroyed call_t structure, we
     636         * must hold a reference to it.
     637         */
     638        ipc_call_hold(call);
     639
     640        spinlock_unlock(&call->forget_lock);
     641        spinlock_unlock(&TASK->active_calls_lock);
     642
     643        atomic_dec(&call->caller_phone->active_calls);
     644
     645        sysipc_ops_t *ops = sysipc_ops_get(call->request_method);
     646        if (ops->request_forget)
     647                ops->request_forget(call);
     648
     649        ipc_call_release(call);
     650
     651        goto restart;
     652}
     653
     654/** Wait for all answers to asynchronous calls to arrive. */
     655static void ipc_wait_for_all_answered_calls(void)
     656{
     657        call_t *call;
     658        size_t i;
     659
     660restart:
     661        /*
     662         * Go through all phones, until they are all free.
     663         * Locking is needed as there may be connection handshakes in progress.
     664         */
     665        for (i = 0; i < IPC_MAX_PHONES; i++) {
     666                phone_t *phone = &TASK->phones[i];
     667
     668                mutex_lock(&phone->lock);       
     669                if ((phone->state == IPC_PHONE_HUNGUP) &&
     670                    (atomic_get(&phone->active_calls) == 0)) {
     671                        phone->state = IPC_PHONE_FREE;
     672                        phone->callee = NULL;
     673                }
     674
     675                /*
     676                 * We might have had some IPC_PHONE_CONNECTING phones at the
     677                 * beginning of ipc_cleanup(). Depending on whether these were
     678                 * forgotten or answered, they will eventually enter the
     679                 * IPC_PHONE_FREE or IPC_PHONE_CONNECTED states, respectively.
     680                 * In the latter case, the other side may slam the open phones
     681                 * at any time, in which case we will get an IPC_PHONE_SLAMMED
     682                 * phone.
     683                 */
     684                if ((phone->state == IPC_PHONE_CONNECTED) ||
     685                    (phone->state == IPC_PHONE_SLAMMED)) {
     686                        mutex_unlock(&phone->lock);
     687                        ipc_phone_hangup(phone);
     688                        /*
     689                         * Now there may be one extra active call, which needs
     690                         * to be forgotten.
     691                         */
     692                        ipc_forget_all_active_calls();
     693                        goto restart;
     694                }
     695
     696                /*
     697                 * If the hangup succeeded, it has sent a HANGUP message, the
     698                 * IPC is now in HUNGUP state, we wait for the reply to come
     699                 */
     700                if (phone->state != IPC_PHONE_FREE) {
     701                        mutex_unlock(&phone->lock);
     702                        break;
     703                }
     704
     705                mutex_unlock(&phone->lock);
     706        }
     707               
     708        /* Got into cleanup */
     709        if (i == IPC_MAX_PHONES)
     710                return;
     711               
     712        call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT,
     713            SYNCH_FLAGS_NONE);
     714        ASSERT(call->flags & (IPC_CALL_ANSWERED | IPC_CALL_NOTIF));
     715        ipc_call_free(call);
     716        goto restart;
     717}
     718
    531719/** Clean up all IPC communication of the current task.
    532720 *
     
    537725void ipc_cleanup(void)
    538726{
     727        /*
     728         * Mark the answerbox as inactive.
     729         *
     730         * The main purpose for doing this is to prevent any pending callback
     731         * connections from getting established beyond this point.
     732         */
     733        irq_spinlock_lock(&TASK->answerbox.lock, true);
     734        TASK->answerbox.active = false;
     735        irq_spinlock_unlock(&TASK->answerbox.lock, true);
     736
    539737        /* Disconnect all our phones ('ipc_phone_hangup') */
    540         size_t i;
    541         for (i = 0; i < IPC_MAX_PHONES; i++)
     738        for (size_t i = 0; i < IPC_MAX_PHONES; i++)
    542739                ipc_phone_hangup(&TASK->phones[i]);
    543740       
     
    557754       
    558755        /* Answer all messages in 'calls' and 'dispatched_calls' queues */
    559         irq_spinlock_lock(&TASK->answerbox.lock, true);
    560         ipc_cleanup_call_list(&TASK->answerbox.dispatched_calls);
    561         ipc_cleanup_call_list(&TASK->answerbox.calls);
    562         irq_spinlock_unlock(&TASK->answerbox.lock, true);
    563        
    564         /* Wait for all answers to asynchronous calls to arrive */
    565         while (true) {
    566                 /*
    567                  * Go through all phones, until they are all FREE
    568                  * Locking is not needed, no one else should modify
    569                  * it when we are in cleanup
    570                  */
    571                 for (i = 0; i < IPC_MAX_PHONES; i++) {
    572                         if (TASK->phones[i].state == IPC_PHONE_HUNGUP &&
    573                             atomic_get(&TASK->phones[i].active_calls) == 0) {
    574                                 TASK->phones[i].state = IPC_PHONE_FREE;
    575                                 TASK->phones[i].callee = NULL;
    576                         }
    577                        
    578                         /*
    579                          * Just for sure, we might have had some
    580                          * IPC_PHONE_CONNECTING phones
    581                          */
    582                         if (TASK->phones[i].state == IPC_PHONE_CONNECTED)
    583                                 ipc_phone_hangup(&TASK->phones[i]);
    584                        
    585                         /*
    586                          * If the hangup succeeded, it has sent a HANGUP
    587                          * message, the IPC is now in HUNGUP state, we
    588                          * wait for the reply to come
    589                          */
    590                        
    591                         if (TASK->phones[i].state != IPC_PHONE_FREE)
    592                                 break;
    593                 }
    594                
    595                 /* Got into cleanup */
    596                 if (i == IPC_MAX_PHONES)
    597                         break;
    598                
    599                 call_t *call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT,
    600                     SYNCH_FLAGS_NONE);
    601                 ASSERT((call->flags & IPC_CALL_ANSWERED) ||
    602                     (call->flags & IPC_CALL_NOTIF));
    603                
    604                 ipc_call_free(call);
    605         }
     756        ipc_cleanup_call_list(&TASK->answerbox,
     757            &TASK->answerbox.dispatched_calls);
     758        ipc_cleanup_call_list(&TASK->answerbox, &TASK->answerbox.calls);
     759
     760        ipc_forget_all_active_calls();
     761        ipc_wait_for_all_answered_calls();
    606762}
    607763
     
    615771        ipc_answerbox_slab = slab_cache_create("answerbox_t",
    616772            sizeof(answerbox_t), 0, NULL, NULL, 0);
     773}
     774
     775
     776static void ipc_print_call_list(list_t *list)
     777{
     778        list_foreach(*list, cur) {
     779                call_t *call = list_get_instance(cur, call_t, ab_link);
     780               
     781#ifdef __32_BITS__
     782                printf("%10p ", call);
     783#endif
     784               
     785#ifdef __64_BITS__
     786                printf("%18p ", call);
     787#endif
     788               
     789                spinlock_lock(&call->forget_lock);
     790
     791                printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
     792                    " %-6" PRIun " %-6" PRIun " %-7x",
     793                    IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
     794                    IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
     795                    IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
     796                    call->flags);
     797
     798                if (call->forget) {
     799                        printf(" ? (call forgotten)\n");
     800                } else {
     801                        printf(" %" PRIu64 " (%s)\n",
     802                            call->sender->taskid, call->sender->name);
     803                }
     804
     805                spinlock_unlock(&call->forget_lock);
     806        }
    617807}
    618808
     
    688878       
    689879        printf(" --- incomming calls ---\n");
    690         list_foreach(task->answerbox.calls, cur) {
    691                 call_t *call = list_get_instance(cur, call_t, link);
    692                
    693 #ifdef __32_BITS__
    694                 printf("%10p ", call);
    695 #endif
    696                
    697 #ifdef __64_BITS__
    698                 printf("%18p ", call);
    699 #endif
    700                
    701                 printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
    702                     " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n",
    703                     IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
    704                     IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
    705                     IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
    706                     call->flags, call->sender->taskid, call->sender->name);
    707         }
    708        
     880        ipc_print_call_list(&task->answerbox.calls);
    709881        printf(" --- dispatched calls ---\n");
    710         list_foreach(task->answerbox.dispatched_calls, cur) {
    711                 call_t *call = list_get_instance(cur, call_t, link);
    712                
    713 #ifdef __32_BITS__
    714                 printf("%10p ", call);
    715 #endif
    716                
    717 #ifdef __64_BITS__
    718                 printf("%18p ", call);
    719 #endif
    720                
    721                 printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
    722                     " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n",
    723                     IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
    724                     IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
    725                     IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
    726                     call->flags, call->sender->taskid, call->sender->name);
    727         }
    728        
     882        ipc_print_call_list(&task->answerbox.dispatched_calls);
    729883        printf(" --- incoming answers ---\n");
    730         list_foreach(task->answerbox.answers, cur) {
    731                 call_t *call = list_get_instance(cur, call_t, link);
    732                
    733 #ifdef __32_BITS__
    734                 printf("%10p ", call);
    735 #endif
    736                
    737 #ifdef __64_BITS__
    738                 printf("%18p ", call);
    739 #endif
    740                
    741                 printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
    742                     " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n",
    743                     IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
    744                     IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
    745                     IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
    746                     call->flags, call->sender->taskid, call->sender->name);
    747         }
     884        ipc_print_call_list(&task->answerbox.answers);
    748885       
    749886        irq_spinlock_unlock(&task->answerbox.lock, false);
  • kernel/generic/src/ipc/ipcrsc.c

    r40b5421 r00b4a68  
    132132#include <ipc/ipcrsc.h>
    133133#include <debug.h>
     134#include <abi/errno.h>
    134135
    135136/** Find call_t * in call table according to callid.
     
    151152       
    152153        list_foreach(TASK->answerbox.dispatched_calls, lst) {
    153                 call_t *call = list_get_instance(lst, call_t, link);
     154                call_t *call = list_get_instance(lst, call_t, ab_link);
    154155                if ((sysarg_t) call == callid) {
    155156                        result = call;
     
    162163}
    163164
     165/** Get phone from the current task by ID.
     166 *
     167 * @param phoneid Phone ID.
     168 * @param phone   Place to store pointer to phone.
     169 *
     170 * @return EOK on success, EINVAL if ID is invalid.
     171 *
     172 */
     173int phone_get(sysarg_t phoneid, phone_t **phone)
     174{
     175        if (phoneid >= IPC_MAX_PHONES)
     176                return EINVAL;
     177       
     178        *phone = &TASK->phones[phoneid];
     179        return EOK;
     180}
     181
    164182/** Allocate new phone slot in the specified task.
    165183 *
     
    176194        size_t i;
    177195        for (i = 0; i < IPC_MAX_PHONES; i++) {
    178                 if ((task->phones[i].state == IPC_PHONE_HUNGUP) &&
    179                     (atomic_get(&task->phones[i].active_calls) == 0))
    180                         task->phones[i].state = IPC_PHONE_FREE;
     196                phone_t *phone = &task->phones[i];
     197
     198                if ((phone->state == IPC_PHONE_HUNGUP) &&
     199                    (atomic_get(&phone->active_calls) == 0))
     200                        phone->state = IPC_PHONE_FREE;
    181201               
    182                 if (task->phones[i].state == IPC_PHONE_FREE) {
    183                         task->phones[i].state = IPC_PHONE_CONNECTING;
     202                if (phone->state == IPC_PHONE_FREE) {
     203                        phone->state = IPC_PHONE_CONNECTING;
    184204                        break;
    185205                }
     
    223243 * @param phoneid Phone handle to be connected.
    224244 * @param box     Answerbox to which to connect the phone handle.
     245 * @return        True if the phone was connected, false otherwise.
    225246 *
    226247 * The procedure _enforces_ that the user first marks the phone
     
    229250 *
    230251 */
    231 void phone_connect(int phoneid, answerbox_t *box)
     252bool phone_connect(int phoneid, answerbox_t *box)
    232253{
    233254        phone_t *phone = &TASK->phones[phoneid];
    234255       
    235256        ASSERT(phone->state == IPC_PHONE_CONNECTING);
    236         ipc_phone_connect(phone, box);
     257        return ipc_phone_connect(phone, box);
    237258}
    238259
  • kernel/generic/src/ipc/irq.c

    r40b5421 r00b4a68  
    510510{
    511511        irq_spinlock_lock(&irq->notif_cfg.answerbox->irq_lock, false);
    512         list_append(&call->link, &irq->notif_cfg.answerbox->irq_notifs);
     512        list_append(&call->ab_link, &irq->notif_cfg.answerbox->irq_notifs);
    513513        irq_spinlock_unlock(&irq->notif_cfg.answerbox->irq_lock, false);
    514514       
  • kernel/generic/src/ipc/kbox.c

    r40b5421 r00b4a68  
    4848{
    4949        /*
     50         * Not really needed, just to be consistent with the meaning of
     51         * answerbox_t.active.
     52         */
     53        irq_spinlock_lock(&TASK->kb.box.lock, true);
     54        TASK->kb.box.active = false;
     55        irq_spinlock_unlock(&TASK->kb.box.lock, true);
     56
     57        /*
    5058         * Only hold kb.cleanup_lock while setting kb.finished -
    5159         * this is enough.
     
    8896       
    8997        /* Answer all messages in 'calls' and 'dispatched_calls' queues. */
    90         irq_spinlock_lock(&TASK->kb.box.lock, true);
    91         ipc_cleanup_call_list(&TASK->kb.box.dispatched_calls);
    92         ipc_cleanup_call_list(&TASK->kb.box.calls);
    93         irq_spinlock_unlock(&TASK->kb.box.lock, true);
     98        ipc_cleanup_call_list(&TASK->kb.box, &TASK->kb.box.dispatched_calls);
     99        ipc_cleanup_call_list(&TASK->kb.box, &TASK->kb.box.calls);
    94100}
    95101
     
    162168        while (!done) {
    163169                call_t *call = ipc_wait_for_call(&TASK->kb.box, SYNCH_NO_TIMEOUT,
    164                         SYNCH_FLAGS_NONE);
     170                    SYNCH_FLAGS_NONE);
    165171               
    166172                if (call == NULL)
     
    236242       
    237243        /* Connect the newly allocated phone to the kbox */
    238         ipc_phone_connect(&TASK->phones[newphid], &task->kb.box);
     244        (void) ipc_phone_connect(&TASK->phones[newphid], &task->kb.box);
    239245       
    240246        if (task->kb.thread != NULL) {
  • kernel/generic/src/ipc/sysipc.c

    r40b5421 r00b4a68  
    3434
    3535#include <arch.h>
    36 #include <proc/task.h>
    37 #include <proc/thread.h>
    3836#include <errno.h>
    3937#include <memstr.h>
    40 #include <debug.h>
    4138#include <ipc/ipc.h>
    4239#include <abi/ipc/methods.h>
    4340#include <ipc/sysipc.h>
     41#include <ipc/sysipc_ops.h>
     42#include <ipc/sysipc_priv.h>
    4443#include <ipc/irq.h>
    4544#include <ipc/ipcrsc.h>
     
    4746#include <ipc/kbox.h>
    4847#include <synch/waitq.h>
    49 #include <udebug/udebug_ipc.h>
    5048#include <arch/interrupt.h>
    5149#include <syscall/copy.h>
    5250#include <security/cap.h>
    5351#include <console/console.h>
    54 #include <mm/as.h>
    5552#include <print.h>
    5653#include <macros.h>
    5754
    58 /**
    59  * Maximum buffer size allowed for IPC_M_DATA_WRITE and IPC_M_DATA_READ
    60  * requests.
    61  */
    62 #define DATA_XFER_LIMIT  (64 * 1024)
    63 
    6455#define STRUCT_TO_USPACE(dst, src)  copy_to_uspace((dst), (src), sizeof(*(src)))
    65 
    66 /** Get phone from the current task by ID.
    67  *
    68  * @param phoneid Phone ID.
    69  * @param phone   Place to store pointer to phone.
    70  *
    71  * @return EOK on success, EINVAL if ID is invalid.
    72  *
    73  */
    74 static int phone_get(sysarg_t phoneid, phone_t **phone)
    75 {
    76         if (phoneid >= IPC_MAX_PHONES)
    77                 return EINVAL;
    78        
    79         *phone = &TASK->phones[phoneid];
    80         return EOK;
    81 }
    8256
    8357/** Decide if the interface and method is a system method.
     
    181155 * @param olddata Saved data of the request.
    182156 *
    183  * @return Return 0 on success or an error code.
    184  *
    185  */
    186 static inline int answer_preprocess(call_t *answer, ipc_data_t *olddata)
    187 {
     157 * @return Return EOK on success or a negative error code.
     158 *
     159 */
     160int answer_preprocess(call_t *answer, ipc_data_t *olddata)
     161{
     162        int rc = EOK;
     163        sysipc_ops_t *ops;
     164
     165        spinlock_lock(&answer->forget_lock);
     166        if (answer->forget) {
     167                /*
     168                 * This is a forgotten call and answer->sender is not valid.
     169                 */
     170                spinlock_unlock(&answer->forget_lock);
     171
     172                ops = sysipc_ops_get(answer->request_method);
     173                if (ops->answer_cleanup)
     174                        ops->answer_cleanup(answer, olddata);
     175
     176                return rc;
     177        } else {
     178                ASSERT(answer->active);
     179
     180                /*
     181                 * Mark the call as inactive to prevent _ipc_answer_free_call()
     182                 * from attempting to remove the call from the active list
     183                 * itself.
     184                 */
     185                answer->active = false;
     186
     187                /*
     188                 * Remove the call from the sender's active call list.
     189                 * We enforce this locking order so that any potential
     190                 * concurrently executing forget operation is forced to
     191                 * release its active_calls_lock and lose the race to
     192                 * forget this soon to be answered call.
     193                 */
     194                spinlock_lock(&answer->sender->active_calls_lock);
     195                list_remove(&answer->ta_link);
     196                spinlock_unlock(&answer->sender->active_calls_lock);
     197        }
     198        spinlock_unlock(&answer->forget_lock);
     199
    188200        if ((native_t) IPC_GET_RETVAL(answer->data) == EHANGUP) {
    189                 /* In case of forward, hangup the forwared phone,
    190                  * not the originator
    191                  */
    192                 mutex_lock(&answer->data.phone->lock);
    193                 irq_spinlock_lock(&TASK->answerbox.lock, true);
    194                 if (answer->data.phone->state == IPC_PHONE_CONNECTED) {
    195                         list_remove(&answer->data.phone->link);
    196                         answer->data.phone->state = IPC_PHONE_SLAMMED;
     201                phone_t *phone = answer->caller_phone;
     202                mutex_lock(&phone->lock);
     203                if (phone->state == IPC_PHONE_CONNECTED) {
     204                        irq_spinlock_lock(&phone->callee->lock, true);
     205                        list_remove(&phone->link);
     206                        phone->state = IPC_PHONE_SLAMMED;
     207                        irq_spinlock_unlock(&phone->callee->lock, true);
    197208                }
    198                 irq_spinlock_unlock(&TASK->answerbox.lock, true);
    199                 mutex_unlock(&answer->data.phone->lock);
     209                mutex_unlock(&phone->lock);
    200210        }
    201211       
    202212        if (!olddata)
    203                 return 0;
    204        
    205         if (IPC_GET_IMETHOD(*olddata) == IPC_M_CONNECTION_CLONE) {
    206                 int phoneid = IPC_GET_ARG1(*olddata);
    207                 phone_t *phone = &TASK->phones[phoneid];
    208                
    209                 if (IPC_GET_RETVAL(answer->data) != EOK) {
    210                         /*
    211                          * The recipient of the cloned phone rejected the offer.
    212                          * In this case, the connection was established at the
    213                          * request time and therefore we need to slam the phone.
    214                          * We don't merely hangup as that would result in
    215                          * sending IPC_M_HUNGUP to the third party on the
    216                          * other side of the cloned phone.
    217                          */
    218                         mutex_lock(&phone->lock);
    219                         if (phone->state == IPC_PHONE_CONNECTED) {
    220                                 irq_spinlock_lock(&phone->callee->lock, true);
    221                                 list_remove(&phone->link);
    222                                 phone->state = IPC_PHONE_SLAMMED;
    223                                 irq_spinlock_unlock(&phone->callee->lock, true);
    224                         }
    225                         mutex_unlock(&phone->lock);
    226                 }
    227         } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_CLONE_ESTABLISH) {
    228                 phone_t *phone = (phone_t *) IPC_GET_ARG5(*olddata);
    229                
    230                 if (IPC_GET_RETVAL(answer->data) != EOK) {
    231                         /*
    232                          * The other party on the cloned phoned rejected our
    233                          * request for connection on the protocol level.
    234                          * We need to break the connection without sending
    235                          * IPC_M_HUNGUP back.
    236                          */
    237                         mutex_lock(&phone->lock);
    238                         if (phone->state == IPC_PHONE_CONNECTED) {
    239                                 irq_spinlock_lock(&phone->callee->lock, true);
    240                                 list_remove(&phone->link);
    241                                 phone->state = IPC_PHONE_SLAMMED;
    242                                 irq_spinlock_unlock(&phone->callee->lock, true);
    243                         }
    244                         mutex_unlock(&phone->lock);
    245                 }
    246         } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_CONNECT_TO_ME) {
    247                 int phoneid = IPC_GET_ARG5(*olddata);
    248                
    249                 if (IPC_GET_RETVAL(answer->data) != EOK) {
    250                         /* The connection was not accepted */
    251                         phone_dealloc(phoneid);
    252                 } else {
    253                         /* The connection was accepted */
    254                         phone_connect(phoneid, &answer->sender->answerbox);
    255                         /* Set 'phone hash' as arg5 of response */
    256                         IPC_SET_ARG5(answer->data,
    257                             (sysarg_t) &TASK->phones[phoneid]);
    258                 }
    259         } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_CONNECT_ME_TO) {
    260                 /* If the users accepted call, connect */
    261                 if (IPC_GET_RETVAL(answer->data) == EOK) {
    262                         ipc_phone_connect((phone_t *) IPC_GET_ARG5(*olddata),
    263                             &TASK->answerbox);
    264                 }
    265         } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_SHARE_OUT) {
    266                 if (!IPC_GET_RETVAL(answer->data)) {
    267                         /* Accepted, handle as_area receipt */
    268                        
    269                         irq_spinlock_lock(&answer->sender->lock, true);
    270                         as_t *as = answer->sender->as;
    271                         irq_spinlock_unlock(&answer->sender->lock, true);
    272                        
    273                         uintptr_t dst_base = (uintptr_t) -1;
    274                         int rc = as_area_share(as, IPC_GET_ARG1(*olddata),
    275                             IPC_GET_ARG2(*olddata), AS, IPC_GET_ARG3(*olddata),
    276                             &dst_base, IPC_GET_ARG1(answer->data));
    277                        
    278                         if (rc == EOK)
    279                                 rc = copy_to_uspace((void *) IPC_GET_ARG2(answer->data),
    280                                     &dst_base, sizeof(dst_base));
    281                        
    282                         IPC_SET_RETVAL(answer->data, rc);
    283                         return rc;
    284                 }
    285         } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_SHARE_IN) {
    286                 if (!IPC_GET_RETVAL(answer->data)) {
    287                         irq_spinlock_lock(&answer->sender->lock, true);
    288                         as_t *as = answer->sender->as;
    289                         irq_spinlock_unlock(&answer->sender->lock, true);
    290                        
    291                         uintptr_t dst_base = (uintptr_t) -1;
    292                         int rc = as_area_share(AS, IPC_GET_ARG1(answer->data),
    293                             IPC_GET_ARG1(*olddata), as, IPC_GET_ARG2(answer->data),
    294                             &dst_base, IPC_GET_ARG3(answer->data));
    295                         IPC_SET_ARG4(answer->data, dst_base);
    296                         IPC_SET_RETVAL(answer->data, rc);
    297                 }
    298         } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_DATA_READ) {
    299                 ASSERT(!answer->buffer);
    300                 if (!IPC_GET_RETVAL(answer->data)) {
    301                         /* The recipient agreed to send data. */
    302                         uintptr_t src = IPC_GET_ARG1(answer->data);
    303                         uintptr_t dst = IPC_GET_ARG1(*olddata);
    304                         size_t max_size = IPC_GET_ARG2(*olddata);
    305                         size_t size = IPC_GET_ARG2(answer->data);
    306                         if (size && size <= max_size) {
    307                                 /*
    308                                  * Copy the destination VA so that this piece of
    309                                  * information is not lost.
    310                                  */
    311                                 IPC_SET_ARG1(answer->data, dst);
    312                                
    313                                 answer->buffer = malloc(size, 0);
    314                                 int rc = copy_from_uspace(answer->buffer,
    315                                     (void *) src, size);
    316                                 if (rc) {
    317                                         IPC_SET_RETVAL(answer->data, rc);
    318                                         free(answer->buffer);
    319                                         answer->buffer = NULL;
    320                                 }
    321                         } else if (!size) {
    322                                 IPC_SET_RETVAL(answer->data, EOK);
    323                         } else {
    324                                 IPC_SET_RETVAL(answer->data, ELIMIT);
    325                         }
    326                 }
    327         } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_DATA_WRITE) {
    328                 ASSERT(answer->buffer);
    329                 if (!IPC_GET_RETVAL(answer->data)) {
    330                         /* The recipient agreed to receive data. */
    331                         uintptr_t dst = (uintptr_t)IPC_GET_ARG1(answer->data);
    332                         size_t size = (size_t)IPC_GET_ARG2(answer->data);
    333                         size_t max_size = (size_t)IPC_GET_ARG2(*olddata);
    334                        
    335                         if (size <= max_size) {
    336                                 int rc = copy_to_uspace((void *) dst,
    337                                     answer->buffer, size);
    338                                 if (rc)
    339                                         IPC_SET_RETVAL(answer->data, rc);
    340                         } else {
    341                                 IPC_SET_RETVAL(answer->data, ELIMIT);
    342                         }
    343                 }
    344                 free(answer->buffer);
    345                 answer->buffer = NULL;
    346         } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_STATE_CHANGE_AUTHORIZE) {
    347                 if (!IPC_GET_RETVAL(answer->data)) {
    348                         /* The recipient authorized the change of state. */
    349                         phone_t *recipient_phone;
    350                         task_t *other_task_s;
    351                         task_t *other_task_r;
    352                         int rc;
    353 
    354                         rc = phone_get(IPC_GET_ARG1(answer->data),
    355                             &recipient_phone);
    356                         if (rc != EOK) {
    357                                 IPC_SET_RETVAL(answer->data, ENOENT);
    358                                 return ENOENT;
    359                         }
    360 
    361                         mutex_lock(&recipient_phone->lock);
    362                         if (recipient_phone->state != IPC_PHONE_CONNECTED) {
    363                                 mutex_unlock(&recipient_phone->lock);
    364                                 IPC_SET_RETVAL(answer->data, EINVAL);
    365                                 return EINVAL;
    366                         }
    367 
    368                         other_task_r = recipient_phone->callee->task;
    369                         other_task_s = (task_t *) IPC_GET_ARG5(*olddata);
    370 
    371                         /*
    372                          * See if both the sender and the recipient meant the
    373                          * same third party task.
    374                          */
    375                         if (other_task_r != other_task_s) {
    376                                 IPC_SET_RETVAL(answer->data, EINVAL);
    377                                 rc = EINVAL;
    378                         } else {
    379                                 rc = event_task_notify_5(other_task_r,
    380                                     EVENT_TASK_STATE_CHANGE, false,
    381                                     IPC_GET_ARG1(*olddata),
    382                                     IPC_GET_ARG2(*olddata),
    383                                     IPC_GET_ARG3(*olddata),
    384                                     LOWER32(olddata->task_id),
    385                                     UPPER32(olddata->task_id));
    386                                 IPC_SET_RETVAL(answer->data, rc);
    387                         }
    388 
    389                         mutex_unlock(&recipient_phone->lock);
    390                         return rc;
    391                 }
    392         }
    393        
    394         return 0;
    395 }
    396 
    397 static void phones_lock(phone_t *p1, phone_t *p2)
    398 {
    399         if (p1 < p2) {
    400                 mutex_lock(&p1->lock);
    401                 mutex_lock(&p2->lock);
    402         } else if (p1 > p2) {
    403                 mutex_lock(&p2->lock);
    404                 mutex_lock(&p1->lock);
    405         } else
    406                 mutex_lock(&p1->lock);
    407 }
    408 
    409 static void phones_unlock(phone_t *p1, phone_t *p2)
    410 {
    411         mutex_unlock(&p1->lock);
    412         if (p1 != p2)
    413                 mutex_unlock(&p2->lock);
     213                return rc;
     214
     215        ops = sysipc_ops_get(answer->request_method);
     216        if (ops->answer_preprocess)
     217                rc = ops->answer_preprocess(answer, olddata);
     218       
     219        return rc;
    414220}
    415221
     
    424230static int request_preprocess(call_t *call, phone_t *phone)
    425231{
    426         switch (IPC_GET_IMETHOD(call->data)) {
    427         case IPC_M_CONNECTION_CLONE: {
    428                 phone_t *cloned_phone;
    429                 if (phone_get(IPC_GET_ARG1(call->data), &cloned_phone) != EOK)
    430                         return ENOENT;
    431                
    432                 phones_lock(cloned_phone, phone);
    433                
    434                 if ((cloned_phone->state != IPC_PHONE_CONNECTED) ||
    435                     phone->state != IPC_PHONE_CONNECTED) {
    436                         phones_unlock(cloned_phone, phone);
    437                         return EINVAL;
    438                 }
    439                
    440                 /*
    441                  * We can be pretty sure now that both tasks exist and we are
    442                  * connected to them. As we continue to hold the phone locks,
    443                  * we are effectively preventing them from finishing their
    444                  * potential cleanup.
    445                  *
    446                  */
    447                 int newphid = phone_alloc(phone->callee->task);
    448                 if (newphid < 0) {
    449                         phones_unlock(cloned_phone, phone);
    450                         return ELIMIT;
    451                 }
    452                
    453                 ipc_phone_connect(&phone->callee->task->phones[newphid],
    454                     cloned_phone->callee);
    455                 phones_unlock(cloned_phone, phone);
    456                
    457                 /* Set the new phone for the callee. */
    458                 IPC_SET_ARG1(call->data, newphid);
    459                 break;
    460         }
    461         case IPC_M_CLONE_ESTABLISH:
    462                 IPC_SET_ARG5(call->data, (sysarg_t) phone);
    463                 break;
    464         case IPC_M_CONNECT_ME_TO: {
    465                 int newphid = phone_alloc(TASK);
    466                 if (newphid < 0)
    467                         return ELIMIT;
    468                
    469                 /* Set arg5 for server */
    470                 IPC_SET_ARG5(call->data, (sysarg_t) &TASK->phones[newphid]);
    471                 call->flags |= IPC_CALL_CONN_ME_TO;
    472                 call->priv = newphid;
    473                 break;
    474         }
    475         case IPC_M_SHARE_OUT: {
    476                 size_t size = as_area_get_size(IPC_GET_ARG1(call->data));
    477                 if (!size)
    478                         return EPERM;
    479                
    480                 IPC_SET_ARG2(call->data, size);
    481                 break;
    482         }
    483         case IPC_M_DATA_READ: {
    484                 size_t size = IPC_GET_ARG2(call->data);
    485                 if (size > DATA_XFER_LIMIT) {
    486                         int flags = IPC_GET_ARG3(call->data);
    487                         if (flags & IPC_XF_RESTRICT)
    488                                 IPC_SET_ARG2(call->data, DATA_XFER_LIMIT);
    489                         else
    490                                 return ELIMIT;
    491                 }
    492                 break;
    493         }
    494         case IPC_M_DATA_WRITE: {
    495                 uintptr_t src = IPC_GET_ARG1(call->data);
    496                 size_t size = IPC_GET_ARG2(call->data);
    497                
    498                 if (size > DATA_XFER_LIMIT) {
    499                         int flags = IPC_GET_ARG3(call->data);
    500                         if (flags & IPC_XF_RESTRICT) {
    501                                 size = DATA_XFER_LIMIT;
    502                                 IPC_SET_ARG2(call->data, size);
    503                         } else
    504                                 return ELIMIT;
    505                 }
    506                
    507                 call->buffer = (uint8_t *) malloc(size, 0);
    508                 int rc = copy_from_uspace(call->buffer, (void *) src, size);
    509                 if (rc != 0) {
    510                         free(call->buffer);
    511                         return rc;
    512                 }
    513                
    514                 break;
    515         }
    516         case IPC_M_STATE_CHANGE_AUTHORIZE: {
    517                 phone_t *sender_phone;
    518                 task_t *other_task_s;
    519 
    520                 if (phone_get(IPC_GET_ARG5(call->data), &sender_phone) != EOK)
    521                         return ENOENT;
    522 
    523                 mutex_lock(&sender_phone->lock);
    524                 if (sender_phone->state != IPC_PHONE_CONNECTED) {
    525                         mutex_unlock(&sender_phone->lock);
    526                         return EINVAL;
    527                 }
    528 
    529                 other_task_s = sender_phone->callee->task;
    530 
    531                 mutex_unlock(&sender_phone->lock);
    532 
    533                 /* Remember the third party task hash. */
    534                 IPC_SET_ARG5(call->data, (sysarg_t) other_task_s);
    535                 break;
    536         }
    537 #ifdef CONFIG_UDEBUG
    538         case IPC_M_DEBUG:
    539                 return udebug_request_preprocess(call, phone);
    540 #endif
    541         default:
    542                 break;
    543         }
    544        
    545         return 0;
     232        int rc = EOK;
     233
     234        call->request_method = IPC_GET_IMETHOD(call->data);
     235
     236        sysipc_ops_t *ops = sysipc_ops_get(call->request_method);
     237        if (ops->request_preprocess)
     238                rc = ops->request_preprocess(call, phone);
     239       
     240        return rc;
    546241}
    547242
     
    561256                IPC_SET_RETVAL(call->data, EFORWARD);
    562257       
    563         if (call->flags & IPC_CALL_CONN_ME_TO) {
    564                 if (IPC_GET_RETVAL(call->data))
    565                         phone_dealloc(call->priv);
    566                 else
    567                         IPC_SET_ARG5(call->data, call->priv);
    568         }
    569        
    570         if (call->buffer) {
    571                 /*
    572                  * This must be an affirmative answer to IPC_M_DATA_READ
    573                  * or IPC_M_DEBUG/UDEBUG_M_MEM_READ...
    574                  *
    575                  */
    576                 uintptr_t dst = IPC_GET_ARG1(call->data);
    577                 size_t size = IPC_GET_ARG2(call->data);
    578                 int rc = copy_to_uspace((void *) dst, call->buffer, size);
    579                 if (rc)
    580                         IPC_SET_RETVAL(call->data, rc);
    581                 free(call->buffer);
    582                 call->buffer = NULL;
    583         }
    584 }
     258        sysipc_ops_t *ops = sysipc_ops_get(call->request_method);
     259        if (ops->answer_process)
     260                (void) ops->answer_process(call);
     261}
     262
    585263
    586264/** Do basic kernel processing of received call request.
     
    595273static int process_request(answerbox_t *box, call_t *call)
    596274{
    597         if (IPC_GET_IMETHOD(call->data) == IPC_M_CONNECT_TO_ME) {
    598                 int phoneid = phone_alloc(TASK);
    599                 if (phoneid < 0) {  /* Failed to allocate phone */
    600                         IPC_SET_RETVAL(call->data, ELIMIT);
    601                         ipc_answer(box, call);
    602                         return -1;
    603                 }
    604                
    605                 IPC_SET_ARG5(call->data, phoneid);
    606         }
    607        
    608         switch (IPC_GET_IMETHOD(call->data)) {
    609         case IPC_M_DEBUG:
    610                 return -1;
    611         default:
    612                 break;
    613         }
    614        
    615         return 0;
     275        int rc = EOK;
     276
     277        sysipc_ops_t *ops = sysipc_ops_get(call->request_method);
     278        if (ops->request_process)
     279                rc = ops->request_process(call, box);
     280       
     281        return rc;
    616282}
    617283
     
    745411{
    746412        call_t *call = get_call(callid);
     413        phone_t *phone;
     414        bool need_old = answer_need_old(call);
     415        bool after_forward = false;
     416        ipc_data_t old;
     417        int rc;
     418
    747419        if (!call)
    748420                return ENOENT;
    749        
     421
     422        if (need_old)
     423                old = call->data;
     424       
     425        if (phone_get(phoneid, &phone) != EOK) {
     426                rc = ENOENT;
     427                goto error;
     428        }
     429       
     430        if (!method_is_forwardable(IPC_GET_IMETHOD(call->data))) {
     431                rc = EPERM;
     432                goto error;
     433        }
     434
    750435        call->flags |= IPC_CALL_FORWARDED;
    751        
    752         phone_t *phone;
    753         if (phone_get(phoneid, &phone) != EOK) {
    754                 IPC_SET_RETVAL(call->data, EFORWARD);
    755                 ipc_answer(&TASK->answerbox, call);
    756                 return ENOENT;
    757         }
    758        
    759         if (!method_is_forwardable(IPC_GET_IMETHOD(call->data))) {
    760                 IPC_SET_RETVAL(call->data, EFORWARD);
    761                 ipc_answer(&TASK->answerbox, call);
    762                 return EPERM;
    763         }
    764436       
    765437        /*
     
    797469        }
    798470       
    799         return ipc_forward(call, phone, &TASK->answerbox, mode);
     471        rc = ipc_forward(call, phone, &TASK->answerbox, mode);
     472        if (rc != EOK) {
     473                after_forward = true;
     474                goto error;
     475        }
     476
     477        return EOK;
     478
     479error:
     480        IPC_SET_RETVAL(call->data, EFORWARD);
     481        (void) answer_preprocess(call, need_old ? &old : NULL);
     482        if (after_forward)
     483                _ipc_answer_free_call(call, false);
     484        else
     485                ipc_answer(&TASK->answerbox, call);
     486
     487        return rc;
    800488}
    801489
  • kernel/generic/src/proc/task.c

    r40b5421 r00b4a68  
    161161        size_t i;
    162162        for (i = 0; i < IPC_MAX_PHONES; i++)
    163                 ipc_phone_init(&task->phones[i]);
     163                ipc_phone_init(&task->phones[i], task);
     164
     165        spinlock_initialize(&task->active_calls_lock, "active_calls_lock");
     166        list_initialize(&task->active_calls);
    164167       
    165168#ifdef CONFIG_UDEBUG
     
    203206        event_task_init(task);
    204207       
     208        task->answerbox.active = true;
     209
    205210#ifdef CONFIG_UDEBUG
    206211        /* Init debugging stuff */
     
    208213       
    209214        /* Init kbox stuff */
     215        task->kb.box.active = true;
    210216        task->kb.finished = false;
    211217#endif
     
    213219        if ((ipc_phone_0) &&
    214220            (container_check(ipc_phone_0->task->container, task->container)))
    215                 ipc_phone_connect(&task->phones[0], ipc_phone_0);
     221                (void) ipc_phone_connect(&task->phones[0], ipc_phone_0);
    216222       
    217223        btree_create(&task->futexes);
Note: See TracChangeset for help on using the changeset viewer.