Ignore:
File:
1 edited

Legend:

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

    r48bcf49 rfeeac0d  
    3939 *
    4040 * The pattern of usage of the resources is:
    41  * - allocate empty phone capability slot, connect | deallocate slot
     41 * - allocate empty phone slot, connect | deallocate slot
    4242 * - disconnect connected phone (some messages might be on the fly)
    4343 * - find phone in slot and send a message using phone
     
    5353 *   atomic on all platforms)
    5454 *
    55  * - To find an empty phone capability slot, the TASK must be locked
     55 * - To find an empty phone 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.
     
    7777 *
    7878 * *** Connect_to_me ***
    79  * The caller sends IPC_M_CONNECT_TO_ME.
     79 * 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
    82  * arise, when the client receives messages from new connection before getting
    83  * response for connect_to_me message. Userspace should implement handshake
    84  * protocol that would control it.
     81 * (RETVAL=0), it can use the phoneid immediately.
     82 * Possible race condition can arise, when the client receives messages from new
     83 * connection before getting response for connect_to_me message. Userspace
     84 * should implement handshake protocol that would control it.
    8585 *
    8686 * Phone hangup
     
    8989 * - The phone is disconnected (no more messages can be sent over this phone),
    9090 *   all in-progress messages are correctly handled. The answerbox receives
    91  *   IPC_M_PHONE_HUNGUP call from the phone that hung up. When all async calls
    92  *   are answered, the phone is deallocated.
     91 *   IPC_M_PHONE_HUNGUP call from the phone that hung up. When all async
     92 *   calls are answered, the phone is deallocated.
    9393 *
    9494 * *** The answerbox hangs up (ipc_answer(EHANGUP))
    95  * - The phone is disconnected. EHANGUP response code is sent to the calling
    96  *   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
    98  *   structures.
    99  *
     95 * - The phone is disconnected. EHANGUP response code is sent
     96 *   to the calling task. All new calls through this phone
     97 *   get a EHUNGUP error code, the task is expected to
     98 *   send an sys_ipc_hangup after cleaning up its internal structures.
    10099 *
    101100 * Call forwarding
    102101 *
    103  * The call can be forwarded, so that the answer to call is passed directly to
    104  * the original sender. However, this poses special problems regarding routing
    105  * of hangup messages.
     102 * The call can be forwarded, so that the answer to call is passed directly
     103 * to the original sender. However, this poses special problems regarding
     104 * routing of hangup messages.
    106105 *
    107106 * sys_ipc_hangup -> IPC_M_PHONE_HUNGUP
     
    132131#include <proc/task.h>
    133132#include <ipc/ipcrsc.h>
    134 #include <assert.h>
     133#include <debug.h>
    135134#include <abi/errno.h>
    136 #include <cap/cap.h>
    137 #include <mm/slab.h>
    138135
    139136/** Find call_t * in call table according to callid.
     
    141138 * @todo Some speedup (hash table?)
    142139 *
    143  * @param callid Userspace hash of the call. Currently it is the call structure
    144  *               kernel address.
    145  *
    146  * @return NULL on not found, otherwise pointer to the call structure.
     140 * @param callid Userspace hash of the call. Currently it is the call
     141 *               structure kernel address.
     142 *
     143 * @return NULL on not found, otherwise pointer to the call
     144 *         structure.
    147145 *
    148146 */
     
    164162}
    165163
    166 static bool phone_reclaim(kobject_t *kobj)
    167 {
    168         bool gc = false;
    169 
    170         mutex_lock(&kobj->phone->lock);
    171         if (kobj->phone->state == IPC_PHONE_HUNGUP &&
    172             atomic_get(&kobj->phone->active_calls) == 0)
    173                 gc = true;
    174         mutex_unlock(&kobj->phone->lock);
    175 
    176         return gc;
    177 }
    178 
    179 static void phone_destroy(void *arg)
    180 {
    181         phone_t *phone = (phone_t *) arg;
    182         slab_free(phone_slab, phone);
    183 }
    184 
    185 static kobject_ops_t phone_kobject_ops = {
    186         .reclaim = phone_reclaim,
    187         .destroy = phone_destroy
    188 };
    189 
    190 
    191 /** Allocate new phone in the specified task.
    192  *
    193  * @param task  Task for which to allocate a new phone.
    194  *
    195  * @return  New phone capability handle.
    196  * @return  Negative error code if a new capability cannot be allocated.
    197  */
    198 cap_handle_t phone_alloc(task_t *task)
    199 {
    200         cap_handle_t handle = cap_alloc(task);
    201         if (handle >= 0) {
    202                 phone_t *phone = slab_alloc(phone_slab, FRAME_ATOMIC);
    203                 if (!phone) {
    204                         cap_free(TASK, handle);
    205                         return ENOMEM;
     164/** Get phone from the current task by ID.
     165 *
     166 * @param phoneid Phone ID.
     167 * @param phone   Place to store pointer to phone.
     168 *
     169 * @return EOK on success, EINVAL if ID is invalid.
     170 *
     171 */
     172int phone_get(sysarg_t phoneid, phone_t **phone)
     173{
     174        if (phoneid >= IPC_MAX_PHONES)
     175                return EINVAL;
     176       
     177        *phone = &TASK->phones[phoneid];
     178        return EOK;
     179}
     180
     181/** Allocate new phone slot in the specified task.
     182 *
     183 * @param task Task for which to allocate a new phone.
     184 *
     185 * @return New phone handle or -1 if the phone handle limit is
     186 *         exceeded.
     187 *
     188 */
     189int phone_alloc(task_t *task)
     190{
     191        irq_spinlock_lock(&task->lock, true);
     192       
     193        size_t i;
     194        for (i = 0; i < IPC_MAX_PHONES; i++) {
     195                phone_t *phone = &task->phones[i];
     196
     197                if ((phone->state == IPC_PHONE_HUNGUP) &&
     198                    (atomic_get(&phone->active_calls) == 0))
     199                        phone->state = IPC_PHONE_FREE;
     200               
     201                if (phone->state == IPC_PHONE_FREE) {
     202                        phone->state = IPC_PHONE_CONNECTING;
     203                        break;
    206204                }
    207                 kobject_t *kobject = malloc(sizeof(kobject_t), FRAME_ATOMIC);
    208                 if (!kobject) {
    209                         cap_free(TASK, handle);
    210                         slab_free(phone_slab, phone);
    211                         return ENOMEM;
    212                 }
    213 
    214                 ipc_phone_init(phone, task);
    215                 phone->state = IPC_PHONE_CONNECTING;
    216 
    217                 kobject_initialize(kobject, KOBJECT_TYPE_PHONE, phone,
    218                     &phone_kobject_ops);
    219                 phone->kobject = kobject;
    220                
    221                 cap_publish(task, handle, kobject);
    222205        }
    223206       
    224         return handle;
     207        irq_spinlock_unlock(&task->lock, true);
     208       
     209        if (i == IPC_MAX_PHONES)
     210                return -1;
     211       
     212        return i;
     213}
     214
     215/** Mark a phone structure free.
     216 *
     217 * @param phone Phone structure to be marked free.
     218 *
     219 */
     220static void phone_deallocp(phone_t *phone)
     221{
     222        ASSERT(phone->state == IPC_PHONE_CONNECTING);
     223       
     224        /* Atomic operation */
     225        phone->state = IPC_PHONE_FREE;
    225226}
    226227
     
    229230 * All already sent messages will be correctly processed.
    230231 *
    231  * @param handle Phone capability handle of the phone to be freed.
    232  *
    233  */
    234 void phone_dealloc(cap_handle_t handle)
    235 {
    236         kobject_t *kobj = cap_unpublish(TASK, handle, KOBJECT_TYPE_PHONE);
    237         if (!kobj)
    238                 return;
    239        
    240         assert(kobj->phone);
    241         assert(kobj->phone->state == IPC_PHONE_CONNECTING);
    242        
    243         kobject_put(kobj);
    244         cap_free(TASK, handle);
     232 * @param phoneid Phone handle of the phone to be freed.
     233 *
     234 */
     235void phone_dealloc(int phoneid)
     236{
     237        phone_deallocp(&TASK->phones[phoneid]);
    245238}
    246239
    247240/** Connect phone to a given answerbox.
    248241 *
    249  * @param handle  Capability handle of the phone to be connected.
    250  * @param box     Answerbox to which to connect the phone.
     242 * @param phoneid Phone handle to be connected.
     243 * @param box     Answerbox to which to connect the phone handle.
    251244 * @return        True if the phone was connected, false otherwise.
    252  */
    253 bool phone_connect(cap_handle_t handle, answerbox_t *box)
    254 {
    255         kobject_t *phone_obj = kobject_get(TASK, handle, KOBJECT_TYPE_PHONE);
    256         if (!phone_obj)
    257                 return false;
    258        
    259         assert(phone_obj->phone->state == IPC_PHONE_CONNECTING);
    260        
    261         /* Hand over phone_obj reference to the answerbox */
    262         return ipc_phone_connect(phone_obj->phone, box);
     245 *
     246 * The procedure _enforces_ that the user first marks the phone
     247 * busy (e.g. via phone_alloc) and then connects the phone, otherwise
     248 * race condition may appear.
     249 *
     250 */
     251bool phone_connect(int phoneid, answerbox_t *box)
     252{
     253        phone_t *phone = &TASK->phones[phoneid];
     254       
     255        ASSERT(phone->state == IPC_PHONE_CONNECTING);
     256        return ipc_phone_connect(phone, box);
    263257}
    264258
Note: See TracChangeset for help on using the changeset viewer.