Changeset 67f11a0 in mainline for kernel/generic/src/ipc/ipcrsc.c


Ignore:
Timestamp:
2018-03-15T17:40:20Z (7 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
530f2de, e9e4068
Parents:
30f1a25 (diff), a36f442 (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.
git-author:
Jakub Jermar <jakub@…> (2018-03-15 17:25:56)
git-committer:
Jakub Jermar <jakub@…> (2018-03-15 17:40:20)
Message:

Merge branch 'noreclaimers'

This commit removes the left-over from the original IPC phone life-cycle
management in which phones were freed lazily during an attempt to
allocate a new phone when the allocator found a hung-up phone with zero
active calls. This mechanism is the reason why kernel objects had to
have the reclaim method. This commit changes the behavior in that phones
are deallocated with their last reference. At the same time it makes
sure that each active call has its own reference on the phone.

This change also makes sure that each connected phone has a capability
via which it can be hung up by the user or cleaned up in ipc_cleanup().
A special mode for phone_alloc() was introduced that allows calls such
as IPC_M_CONNECT_ME_TO and IPC_M_CONNECT_TO_ME to allocate an
unpublished capability and publish it only when the phone is
successfully connected. This fixes a nasty race condition when the user
destroys the capability before the phone is connected and then this
phone becomes essentially invisible for ipc_cleanup().

Last but not least, ipc_cleanup() was slightly streamlined in that it
now knows for how many calls it has to wait from the answerbox's active
call count.

File:
1 edited

Legend:

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

    r30f1a25 r67f11a0  
    3939 *
    4040 * The pattern of usage of the resources is:
    41  * - allocate empty phone capability slot, connect | deallocate slot
     41 * - allocate a capability and phone kernel object (do not publish yet),
     42 *   connect to the answerbox, and finally publish the capability
    4243 * - disconnect connected phone (some messages might be on the fly)
    43  * - find phone in slot and send a message using phone
     44 * - find phone capability and send a message using phone
    4445 * - answer message to phone
    4546 * - hangup phone (the caller has hung up)
     
    5354 *   atomic on all platforms)
    5455 *
    55  * - To find an empty phone capability slot, the TASK must be locked
    5656 * - To answer a message, the answerbox must be locked
    5757 * - The locking of phone and answerbox is done at the ipc_ level.
     
    7373 * *** Connect_me_to ***
    7474 * The caller sends IPC_M_CONNECT_ME_TO to an answerbox. The server receives
    75  * 'phoneid' of the connecting phone as an ARG5. If it answers with RETVAL=0,
    76  * the phonecall is accepted, otherwise it is refused.
     75 * 'phoneid' of the connecting phone as an ARG5. If it answers with RETVAL=EOK,
     76 * the phone call is accepted, otherwise it is refused.
    7777 *
    7878 * *** Connect_to_me ***
    7979 * The caller sends IPC_M_CONNECT_TO_ME.
    8080 * The server receives an automatically opened phoneid. If it accepts
    81  * (RETVAL=0), it can use the phoneid immediately. Possible race condition can
     81 * (RETVAL=EOK), it can use the phoneid immediately. Possible race condition can
    8282 * arise, when the client receives messages from new connection before getting
    8383 * response for connect_to_me message. Userspace should implement handshake
     
    9595 * - The phone is disconnected. EHANGUP response code is sent to the calling
    9696 *   task. All new calls through this phone get a EHUNGUP error code, the task
    97  *   is expected to send an sys_ipc_hangup after cleaning up its internal
     97 *   is expected to call sys_ipc_hangup after cleaning up its internal
    9898 *   structures.
    9999 *
     
    137137#include <mm/slab.h>
    138138
    139 static bool phone_reclaim(kobject_t *kobj)
    140 {
    141         bool gc = false;
    142 
    143         mutex_lock(&kobj->phone->lock);
    144         if (kobj->phone->state == IPC_PHONE_HUNGUP &&
    145             atomic_get(&kobj->phone->active_calls) == 0)
    146                 gc = true;
    147         mutex_unlock(&kobj->phone->lock);
    148 
    149         return gc;
    150 }
    151 
    152139static void phone_destroy(void *arg)
    153140{
     
    157144
    158145static kobject_ops_t phone_kobject_ops = {
    159         .reclaim = phone_reclaim,
    160146        .destroy = phone_destroy
    161147};
     
    164150/** Allocate new phone in the specified task.
    165151 *
    166  * @param task  Task for which to allocate a new phone.
    167  *
    168  * @param[out] out_handle  New phone capability handle.
     152 * @param[in]  task     Task for which to allocate a new phone.
     153 * @param[in]  publish  If true, the new capability will be published.
     154 * @param[out] phandle  New phone capability handle.
     155 * @param[out] kobject  New phone kobject.
    169156 *
    170157 * @return  An error code if a new capability cannot be allocated.
    171158 */
    172 errno_t phone_alloc(task_t *task, cap_handle_t *out_handle)
     159errno_t phone_alloc(task_t *task, bool publish, cap_handle_t *phandle,
     160    kobject_t **kobject)
    173161{
    174162        cap_handle_t handle;
     
    180168                        return ENOMEM;
    181169                }
    182                 kobject_t *kobject = malloc(sizeof(kobject_t), FRAME_ATOMIC);
    183                 if (!kobject) {
     170                kobject_t *kobj = malloc(sizeof(kobject_t), FRAME_ATOMIC);
     171                if (!kobj) {
    184172                        cap_free(TASK, handle);
    185173                        slab_free(phone_cache, phone);
     
    190178                phone->state = IPC_PHONE_CONNECTING;
    191179
    192                 kobject_initialize(kobject, KOBJECT_TYPE_PHONE, phone,
     180                kobject_initialize(kobj, KOBJECT_TYPE_PHONE, phone,
    193181                    &phone_kobject_ops);
    194                 phone->kobject = kobject;
    195 
    196                 cap_publish(task, handle, kobject);
    197 
    198                 *out_handle = handle;
     182                phone->kobject = kobj;
     183
     184                if (publish)
     185                        cap_publish(task, handle, kobj);
     186
     187                *phandle = handle;
     188                if (kobject)
     189                        *kobject = kobj;
    199190        }
    200191        return rc;
     
    214205                return;
    215206
    216         assert(kobj->phone);
    217         assert(kobj->phone->state == IPC_PHONE_CONNECTING);
    218 
    219207        kobject_put(kobj);
    220208        cap_free(TASK, handle);
    221209}
    222210
    223 /** Connect phone to a given answerbox.
    224  *
    225  * @param handle  Capability handle of the phone to be connected.
    226  * @param box     Answerbox to which to connect the phone.
    227  * @return        True if the phone was connected, false otherwise.
    228  */
    229 bool phone_connect(cap_handle_t handle, answerbox_t *box)
    230 {
    231         kobject_t *phone_obj = kobject_get(TASK, handle, KOBJECT_TYPE_PHONE);
    232         if (!phone_obj)
    233                 return false;
    234 
    235         assert(phone_obj->phone->state == IPC_PHONE_CONNECTING);
    236 
    237         /* Hand over phone_obj reference to the answerbox */
    238         return ipc_phone_connect(phone_obj->phone, box);
    239 }
    240 
    241211/** @}
    242212 */
Note: See TracChangeset for help on using the changeset viewer.