Changes in / [00b4a68:40b5421] in mainline


Ignore:
Files:
13 deleted
13 edited

Legend:

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

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

    r00b4a68 r40b5421  
    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 \
    270259        generic/src/ipc/ipcrsc.c \
    271260        generic/src/ipc/irq.c \
  • kernel/generic/include/config.h

    r00b4a68 r40b5421  
    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)
    5650
    5751#ifndef __ASM__
  • kernel/generic/include/ipc/ipc.h

    r00b4a68 r40b5421  
    6565        mutex_t lock;
    6666        link_t link;
    67         struct task *caller;
    6867        struct answerbox *callee;
    6968        ipc_phone_state_t state;
     
    7372typedef struct answerbox {
    7473        IRQ_SPINLOCK_DECLARE(lock);
    75 
    76         /** Answerbox is active until it enters cleanup. */
    77         bool active;
    7874       
    7975        struct task *task;
     
    110106
    111107typedef struct {
    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;
     108        link_t link;
    123109       
    124110        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;
    142111       
    143         /**
    144          * Identification of the caller.
    145          * Valid only when the call is not forgotten.
    146          */
     112        /** Identification of the caller. */
    147113        struct task *sender;
    148        
    149         /** Phone which was used to send the call. */
    150         phone_t *caller_phone;
    151114       
    152115        /** Private data to internal IPC. */
     
    155118        /** Data passed from/to userspace. */
    156119        ipc_data_t data;
    157 
    158         /** Method as it was sent in the request. */
    159         sysarg_t request_method;
    160 
     120       
    161121        /** Buffer for IPC_M_DATA_WRITE and IPC_M_DATA_READ. */
    162122        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;
    163130} call_t;
    164131
     
    169136extern call_t *ipc_call_alloc(unsigned int);
    170137extern void ipc_call_free(call_t *);
    171 extern void ipc_call_hold(call_t *);
    172 extern void ipc_call_release(call_t *);
    173138
    174139extern int ipc_call(phone_t *, call_t *);
     
    176141extern int ipc_forward(call_t *, phone_t *, answerbox_t *, unsigned int);
    177142extern void ipc_answer(answerbox_t *, call_t *);
    178 extern void _ipc_answer_free_call(call_t *, bool);
    179143
    180 extern void ipc_phone_init(phone_t *, struct task *);
    181 extern bool ipc_phone_connect(phone_t *, answerbox_t *);
     144extern void ipc_phone_init(phone_t *);
     145extern void ipc_phone_connect(phone_t *, answerbox_t *);
    182146extern int ipc_phone_hangup(phone_t *);
    183147
     
    187151extern void ipc_backsend_err(phone_t *, call_t *, sysarg_t);
    188152extern void ipc_answerbox_slam_phones(answerbox_t *, bool);
    189 extern void ipc_cleanup_call_list(answerbox_t *, list_t *);
     153extern void ipc_cleanup_call_list(list_t *);
    190154
    191155extern void ipc_print_task(task_id_t);
  • kernel/generic/include/ipc/ipcrsc.h

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

    r00b4a68 r40b5421  
    9191       
    9292        /* IPC stuff */
    93 
    94         /** Receiving communication endpoint */
    95         answerbox_t answerbox;
    96 
    97         /** Sending communication endpoints */
     93        answerbox_t answerbox;  /**< Communication endpoint */
    9894        phone_t phones[IPC_MAX_PHONES];
    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 
     95        stats_ipc_t ipc_info;   /**< IPC statistics */
    10996        event_t events[EVENT_TASK_END - EVENT_END];
    110 
    111         /** IPC statistics */
    112         stats_ipc_t ipc_info;
    11397       
    11498#ifdef CONFIG_UDEBUG
  • kernel/generic/src/ipc/event.c

    r00b4a68 r40b5421  
    163163                                call->data.task_id = TASK ? TASK->taskid : 0;
    164164                               
    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);
     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);
    174170                               
    175171                                if (mask)
  • kernel/generic/src/ipc/ipc.c

    r00b4a68 r40b5421  
    4545#include <ipc/kbox.h>
    4646#include <ipc/event.h>
    47 #include <ipc/sysipc_ops.h>
    48 #include <ipc/sysipc_priv.h>
    4947#include <errno.h>
    5048#include <mm/slab.h>
     
    7371{
    7472        memsetb(call, sizeof(*call), 0);
    75         spinlock_initialize(&call->forget_lock, "forget_lock");
    76         call->active = false;
    77         call->forget = false;
    78         call->sender = NULL;
     73        call->sender = TASK;
    7974        call->buffer = NULL;
    80 }
    81 
    82 void ipc_call_hold(call_t *call)
    83 {
    84         atomic_inc(&call->refcnt);
    85 }
    86 
    87 void 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         }
    9475}
    9576
     
    10283 *
    10384 * @return If flags permit it, return NULL, or initialized kernel
    104  *         call structure with one reference.
     85 *         call structure.
    10586 *
    10687 */
     
    10889{
    10990        call_t *call = slab_alloc(ipc_call_slab, flags);
    110         if (call) {
     91        if (call)
    11192                _ipc_call_init(call);
    112                 ipc_call_hold(call);
    113         }
    11493       
    11594        return call;
     
    123102void ipc_call_free(call_t *call)
    124103{
    125         ipc_call_release(call);
     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);
    126108}
    127109
     
    150132 * @param phone Initialized phone structure.
    151133 * @param box   Initialized answerbox structure.
    152  * @return      True if the phone was connected, false otherwise.
    153  */
    154 bool ipc_phone_connect(phone_t *phone, answerbox_t *box)
    155 {
    156         bool active;
    157 
     134 *
     135 */
     136void ipc_phone_connect(phone_t *phone, answerbox_t *box)
     137{
    158138        mutex_lock(&phone->lock);
     139       
     140        phone->state = IPC_PHONE_CONNECTED;
     141        phone->callee = box;
     142       
    159143        irq_spinlock_lock(&box->lock, true);
    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 
     144        list_append(&phone->link, &box->connected_phones);
    168145        irq_spinlock_unlock(&box->lock, true);
     146       
    169147        mutex_unlock(&phone->lock);
    170 
    171         return active;
    172148}
    173149
     
    175151 *
    176152 * @param phone Phone structure to be initialized.
    177  * @param caller Owning task.
    178  *
    179  */
    180 void ipc_phone_init(phone_t *phone, task_t *caller)
     153 *
     154 */
     155void ipc_phone_init(phone_t *phone)
    181156{
    182157        mutex_initialize(&phone->lock, MUTEX_PASSIVE);
    183         phone->caller = caller;
    184158        phone->callee = NULL;
    185159        phone->state = IPC_PHONE_FREE;
     
    193167 *
    194168 */
    195 void _ipc_answer_free_call(call_t *call, bool selflocked)
    196 {
     169static 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       
    197174        /* Count sent answer */
    198175        irq_spinlock_lock(&TASK->lock, true);
    199176        TASK->ipc_info.answer_sent++;
    200177        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);
     178       
     179        call->flags |= IPC_CALL_ANSWERED;
     180       
     181        if (call->flags & IPC_CALL_FORWARDED) {
     182                if (call->caller_phone) {
     183                        /* Demasquerade the caller phone. */
     184                        call->data.phone = call->caller_phone;
    218185                }
    219186        }
    220         spinlock_unlock(&call->forget_lock);
    221 
    222         answerbox_t *callerbox = &call->sender->answerbox;
    223         bool do_lock = ((!selflocked) || (callerbox != &TASK->answerbox));
    224        
    225         call->flags |= IPC_CALL_ANSWERED;
    226        
     187
    227188        call->data.task_id = TASK->taskid;
    228189       
     
    230191                irq_spinlock_lock(&callerbox->lock, true);
    231192       
    232         list_append(&call->ab_link, &callerbox->answers);
     193        list_append(&call->link, &callerbox->answers);
    233194       
    234195        if (do_lock)
     
    248209        /* Remove from active box */
    249210        irq_spinlock_lock(&box->lock, true);
    250         list_remove(&call->ab_link);
     211        list_remove(&call->link);
    251212        irq_spinlock_unlock(&box->lock, true);
    252213       
     
    267228void ipc_backsend_err(phone_t *phone, call_t *call, sysarg_t err)
    268229{
    269         task_t *caller = phone->caller;
    270 
     230        call->data.phone = phone;
    271231        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 
    280         call->data.phone = phone;
    281 
    282232        IPC_SET_RETVAL(call->data, err);
    283233        _ipc_answer_free_call(call, false);
     
    293243static void _ipc_call(phone_t *phone, answerbox_t *box, call_t *call)
    294244{
    295         task_t *caller = phone->caller;
    296 
    297245        /* Count sent ipc call */
    298         irq_spinlock_lock(&caller->lock, true);
    299         caller->ipc_info.call_sent++;
    300         irq_spinlock_unlock(&caller->lock, true);
     246        irq_spinlock_lock(&TASK->lock, true);
     247        TASK->ipc_info.call_sent++;
     248        irq_spinlock_unlock(&TASK->lock, true);
    301249       
    302250        if (!(call->flags & IPC_CALL_FORWARDED)) {
    303251                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 
    312252                call->data.phone = phone;
    313                 call->data.task_id = caller->taskid;
     253                call->data.task_id = TASK->taskid;
    314254        }
    315255       
    316256        irq_spinlock_lock(&box->lock, true);
    317         list_append(&call->ab_link, &box->calls);
     257        list_append(&call->link, &box->calls);
    318258        irq_spinlock_unlock(&box->lock, true);
    319259       
     
    335275        if (phone->state != IPC_PHONE_CONNECTED) {
    336276                mutex_unlock(&phone->lock);
    337                 if (!(call->flags & IPC_CALL_FORWARDED)) {
     277                if (call->flags & IPC_CALL_FORWARDED) {
     278                        IPC_SET_RETVAL(call->data, EFORWARD);
     279                        _ipc_answer_free_call(call, false);
     280                } else {
    338281                        if (phone->state == IPC_PHONE_HUNGUP)
    339282                                ipc_backsend_err(phone, call, EHANGUP);
     
    382325                call_t *call = ipc_call_alloc(0);
    383326                IPC_SET_IMETHOD(call->data, IPC_M_PHONE_HUNGUP);
    384                 call->request_method = IPC_M_PHONE_HUNGUP;
    385327                call->flags |= IPC_CALL_DISCARD_ANSWER;
    386328                _ipc_call(phone, box, call);
     
    414356        TASK->ipc_info.forwarded++;
    415357        irq_spinlock_pass(&TASK->lock, &oldbox->lock);
    416         list_remove(&call->ab_link);
     358        list_remove(&call->link);
    417359        irq_spinlock_unlock(&oldbox->lock, true);
    418360       
    419361        if (mode & IPC_FF_ROUTE_FROM_ME) {
     362                if (!call->caller_phone)
     363                        call->caller_phone = call->data.phone;
    420364                call->data.phone = newphone;
    421365                call->data.task_id = TASK->taskid;
     
    462406               
    463407                request = list_get_instance(list_first(&box->irq_notifs),
    464                     call_t, ab_link);
    465                 list_remove(&request->ab_link);
     408                    call_t, link);
     409                list_remove(&request->link);
    466410               
    467411                irq_spinlock_unlock(&box->irq_lock, false);
     
    472416                /* Handle asynchronous answers */
    473417                request = list_get_instance(list_first(&box->answers),
    474                     call_t, ab_link);
    475                 list_remove(&request->ab_link);
    476                 atomic_dec(&request->caller_phone->active_calls);
     418                    call_t, link);
     419                list_remove(&request->link);
     420                atomic_dec(&request->data.phone->active_calls);
    477421        } else if (!list_empty(&box->calls)) {
    478422                /* Count received call */
     
    481425                /* Handle requests */
    482426                request = list_get_instance(list_first(&box->calls),
    483                     call_t, ab_link);
    484                 list_remove(&request->ab_link);
     427                    call_t, link);
     428                list_remove(&request->link);
    485429               
    486430                /* Append request to dispatch queue */
    487                 list_append(&request->ab_link, &box->dispatched_calls);
     431                list_append(&request->link, &box->dispatched_calls);
    488432        } else {
    489433                /* This can happen regularly after ipc_cleanup */
     
    505449/** Answer all calls from list with EHANGUP answer.
    506450 *
    507  * @param box Answerbox with the list.
    508451 * @param lst Head of the list to be cleaned up.
    509  */
    510 void ipc_cleanup_call_list(answerbox_t *box, list_t *lst)
    511 {
    512         irq_spinlock_lock(&box->lock, true);
     452 *
     453 */
     454void ipc_cleanup_call_list(list_t *lst)
     455{
    513456        while (!list_empty(lst)) {
    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;
     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               
    522463                IPC_SET_RETVAL(call->data, EHANGUP);
    523                 answer_preprocess(call, &old);
    524464                _ipc_answer_free_call(call, true);
    525 
    526                 irq_spinlock_lock(&box->lock, true);
    527         }
    528         irq_spinlock_unlock(&box->lock, true);
     465        }
    529466}
    530467
     
    564501                        mutex_unlock(&phone->lock);
    565502                        irq_spinlock_unlock(&box->lock, true);
    566 
    567                         // FIXME: phone can become deallocated at any time now
    568 
     503                       
    569504                        /*
    570505                         * Send one message to the answerbox for each
     
    574509                         */
    575510                        IPC_SET_IMETHOD(call->data, IPC_M_PHONE_HUNGUP);
    576                         call->request_method = IPC_M_PHONE_HUNGUP;
    577511                        call->flags |= IPC_CALL_DISCARD_ANSWER;
    578512                        _ipc_call(phone, box, call);
     
    595529}
    596530
    597 static void ipc_forget_all_active_calls(void)
    598 {
    599         call_t *call;
    600 
    601 restart:
    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. */
    655 static void ipc_wait_for_all_answered_calls(void)
    656 {
    657         call_t *call;
    658         size_t i;
    659 
    660 restart:
    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 
    719531/** Clean up all IPC communication of the current task.
    720532 *
     
    725537void ipc_cleanup(void)
    726538{
    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 
    737539        /* Disconnect all our phones ('ipc_phone_hangup') */
    738         for (size_t i = 0; i < IPC_MAX_PHONES; i++)
     540        size_t i;
     541        for (i = 0; i < IPC_MAX_PHONES; i++)
    739542                ipc_phone_hangup(&TASK->phones[i]);
    740543       
     
    754557       
    755558        /* Answer all messages in 'calls' and 'dispatched_calls' queues */
    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();
     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        }
    762606}
    763607
     
    771615        ipc_answerbox_slab = slab_cache_create("answerbox_t",
    772616            sizeof(answerbox_t), 0, NULL, NULL, 0);
    773 }
    774 
    775 
    776 static 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         }
    807617}
    808618
     
    878688       
    879689        printf(" --- incomming calls ---\n");
    880         ipc_print_call_list(&task->answerbox.calls);
     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       
    881709        printf(" --- dispatched calls ---\n");
    882         ipc_print_call_list(&task->answerbox.dispatched_calls);
     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       
    883729        printf(" --- incoming answers ---\n");
    884         ipc_print_call_list(&task->answerbox.answers);
     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        }
    885748       
    886749        irq_spinlock_unlock(&task->answerbox.lock, false);
  • kernel/generic/src/ipc/ipcrsc.c

    r00b4a68 r40b5421  
    132132#include <ipc/ipcrsc.h>
    133133#include <debug.h>
    134 #include <abi/errno.h>
    135134
    136135/** Find call_t * in call table according to callid.
     
    152151       
    153152        list_foreach(TASK->answerbox.dispatched_calls, lst) {
    154                 call_t *call = list_get_instance(lst, call_t, ab_link);
     153                call_t *call = list_get_instance(lst, call_t, link);
    155154                if ((sysarg_t) call == callid) {
    156155                        result = call;
     
    163162}
    164163
    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  */
    173 int 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 
    182164/** Allocate new phone slot in the specified task.
    183165 *
     
    194176        size_t i;
    195177        for (i = 0; i < IPC_MAX_PHONES; i++) {
    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;
     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;
    201181               
    202                 if (phone->state == IPC_PHONE_FREE) {
    203                         phone->state = IPC_PHONE_CONNECTING;
     182                if (task->phones[i].state == IPC_PHONE_FREE) {
     183                        task->phones[i].state = IPC_PHONE_CONNECTING;
    204184                        break;
    205185                }
     
    243223 * @param phoneid Phone handle to be connected.
    244224 * @param box     Answerbox to which to connect the phone handle.
    245  * @return        True if the phone was connected, false otherwise.
    246225 *
    247226 * The procedure _enforces_ that the user first marks the phone
     
    250229 *
    251230 */
    252 bool phone_connect(int phoneid, answerbox_t *box)
     231void phone_connect(int phoneid, answerbox_t *box)
    253232{
    254233        phone_t *phone = &TASK->phones[phoneid];
    255234       
    256235        ASSERT(phone->state == IPC_PHONE_CONNECTING);
    257         return ipc_phone_connect(phone, box);
     236        ipc_phone_connect(phone, box);
    258237}
    259238
  • kernel/generic/src/ipc/irq.c

    r00b4a68 r40b5421  
    510510{
    511511        irq_spinlock_lock(&irq->notif_cfg.answerbox->irq_lock, false);
    512         list_append(&call->ab_link, &irq->notif_cfg.answerbox->irq_notifs);
     512        list_append(&call->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

    r00b4a68 r40b5421  
    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         /*
    5850         * Only hold kb.cleanup_lock while setting kb.finished -
    5951         * this is enough.
     
    9688       
    9789        /* Answer all messages in 'calls' and 'dispatched_calls' queues. */
    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);
     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);
    10094}
    10195
     
    168162        while (!done) {
    169163                call_t *call = ipc_wait_for_call(&TASK->kb.box, SYNCH_NO_TIMEOUT,
    170                     SYNCH_FLAGS_NONE);
     164                        SYNCH_FLAGS_NONE);
    171165               
    172166                if (call == NULL)
     
    242236       
    243237        /* Connect the newly allocated phone to the kbox */
    244         (void) ipc_phone_connect(&TASK->phones[newphid], &task->kb.box);
     238        ipc_phone_connect(&TASK->phones[newphid], &task->kb.box);
    245239       
    246240        if (task->kb.thread != NULL) {
  • kernel/generic/src/ipc/sysipc.c

    r00b4a68 r40b5421  
    3434
    3535#include <arch.h>
     36#include <proc/task.h>
     37#include <proc/thread.h>
    3638#include <errno.h>
    3739#include <memstr.h>
     40#include <debug.h>
    3841#include <ipc/ipc.h>
    3942#include <abi/ipc/methods.h>
    4043#include <ipc/sysipc.h>
    41 #include <ipc/sysipc_ops.h>
    42 #include <ipc/sysipc_priv.h>
    4344#include <ipc/irq.h>
    4445#include <ipc/ipcrsc.h>
     
    4647#include <ipc/kbox.h>
    4748#include <synch/waitq.h>
     49#include <udebug/udebug_ipc.h>
    4850#include <arch/interrupt.h>
    4951#include <syscall/copy.h>
    5052#include <security/cap.h>
    5153#include <console/console.h>
     54#include <mm/as.h>
    5255#include <print.h>
    5356#include <macros.h>
    5457
     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
    5564#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 */
     74static 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}
    5682
    5783/** Decide if the interface and method is a system method.
     
    155181 * @param olddata Saved data of the request.
    156182 *
    157  * @return Return EOK on success or a negative error code.
    158  *
    159  */
    160 int 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.
     183 * @return Return 0 on success or an error code.
     184 *
     185 */
     186static inline int answer_preprocess(call_t *answer, ipc_data_t *olddata)
     187{
     188        if ((native_t) IPC_GET_RETVAL(answer->data) == EHANGUP) {
     189                /* In case of forward, hangup the forwared phone,
     190                 * not the originator
    169191                 */
    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 
    200         if ((native_t) IPC_GET_RETVAL(answer->data) == EHANGUP) {
    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);
    208                 }
    209                 mutex_unlock(&phone->lock);
     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;
     197                }
     198                irq_spinlock_unlock(&TASK->answerbox.lock, true);
     199                mutex_unlock(&answer->data.phone->lock);
    210200        }
    211201       
    212202        if (!olddata)
    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;
     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
     397static 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
     409static void phones_unlock(phone_t *p1, phone_t *p2)
     410{
     411        mutex_unlock(&p1->lock);
     412        if (p1 != p2)
     413                mutex_unlock(&p2->lock);
    220414}
    221415
     
    230424static int request_preprocess(call_t *call, phone_t *phone)
    231425{
    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;
     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;
    241546}
    242547
     
    256561                IPC_SET_RETVAL(call->data, EFORWARD);
    257562       
    258         sysipc_ops_t *ops = sysipc_ops_get(call->request_method);
    259         if (ops->answer_process)
    260                 (void) ops->answer_process(call);
    261 }
    262 
     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}
    263585
    264586/** Do basic kernel processing of received call request.
     
    273595static int process_request(answerbox_t *box, call_t *call)
    274596{
    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;
     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;
    282616}
    283617
     
    411745{
    412746        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 
    419747        if (!call)
    420748                return ENOENT;
    421 
    422         if (need_old)
    423                 old = call->data;
    424        
     749       
     750        call->flags |= IPC_CALL_FORWARDED;
     751       
     752        phone_t *phone;
    425753        if (phone_get(phoneid, &phone) != EOK) {
    426                 rc = ENOENT;
    427                 goto error;
     754                IPC_SET_RETVAL(call->data, EFORWARD);
     755                ipc_answer(&TASK->answerbox, call);
     756                return ENOENT;
    428757        }
    429758       
    430759        if (!method_is_forwardable(IPC_GET_IMETHOD(call->data))) {
    431                 rc = EPERM;
    432                 goto error;
    433         }
    434 
    435         call->flags |= IPC_CALL_FORWARDED;
     760                IPC_SET_RETVAL(call->data, EFORWARD);
     761                ipc_answer(&TASK->answerbox, call);
     762                return EPERM;
     763        }
    436764       
    437765        /*
     
    469797        }
    470798       
    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 
    479 error:
    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;
     799        return ipc_forward(call, phone, &TASK->answerbox, mode);
    488800}
    489801
  • kernel/generic/src/proc/task.c

    r00b4a68 r40b5421  
    161161        size_t i;
    162162        for (i = 0; i < IPC_MAX_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);
     163                ipc_phone_init(&task->phones[i]);
    167164       
    168165#ifdef CONFIG_UDEBUG
     
    206203        event_task_init(task);
    207204       
    208         task->answerbox.active = true;
    209 
    210205#ifdef CONFIG_UDEBUG
    211206        /* Init debugging stuff */
     
    213208       
    214209        /* Init kbox stuff */
    215         task->kb.box.active = true;
    216210        task->kb.finished = false;
    217211#endif
     
    219213        if ((ipc_phone_0) &&
    220214            (container_check(ipc_phone_0->task->container, task->container)))
    221                 (void) ipc_phone_connect(&task->phones[0], ipc_phone_0);
     215                ipc_phone_connect(&task->phones[0], ipc_phone_0);
    222216       
    223217        btree_create(&task->futexes);
Note: See TracChangeset for help on using the changeset viewer.