Changes in kernel/generic/src/ipc/ipcrsc.c [48bcf49:feeac0d] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/ipc/ipcrsc.c
r48bcf49 rfeeac0d 39 39 * 40 40 * The pattern of usage of the resources is: 41 * - allocate empty phone capabilityslot, connect | deallocate slot41 * - allocate empty phone slot, connect | deallocate slot 42 42 * - disconnect connected phone (some messages might be on the fly) 43 43 * - find phone in slot and send a message using phone … … 53 53 * atomic on all platforms) 54 54 * 55 * - To find an empty phone capabilityslot, the TASK must be locked55 * - To find an empty phone slot, the TASK must be locked 56 56 * - To answer a message, the answerbox must be locked 57 57 * - The locking of phone and answerbox is done at the ipc_ level. … … 77 77 * 78 78 * *** Connect_to_me *** 79 * The caller sends IPC_M_CONNECT_TO_ME. 79 * The caller sends IPC_M_CONNECT_TO_ME. 80 80 * The server receives an automatically opened phoneid. If it accepts 81 * (RETVAL=0), it can use the phoneid immediately. Possible race condition can82 * arise, when the client receives messages from new connection before getting83 * response for connect_to_me message. Userspace should implement handshake84 * 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. 85 85 * 86 86 * Phone hangup … … 89 89 * - The phone is disconnected (no more messages can be sent over this phone), 90 90 * 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 calls92 * 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. 93 93 * 94 94 * *** 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. 100 99 * 101 100 * Call forwarding 102 101 * 103 * The call can be forwarded, so that the answer to call is passed directly to104 * t he original sender. However, this poses special problems regarding routing105 * 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. 106 105 * 107 106 * sys_ipc_hangup -> IPC_M_PHONE_HUNGUP … … 132 131 #include <proc/task.h> 133 132 #include <ipc/ipcrsc.h> 134 #include < assert.h>133 #include <debug.h> 135 134 #include <abi/errno.h> 136 #include <cap/cap.h>137 #include <mm/slab.h>138 135 139 136 /** Find call_t * in call table according to callid. … … 141 138 * @todo Some speedup (hash table?) 142 139 * 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. 147 145 * 148 146 */ … … 164 162 } 165 163 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 */ 172 int 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 */ 189 int 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; 206 204 } 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);222 205 } 223 206 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 */ 220 static void phone_deallocp(phone_t *phone) 221 { 222 ASSERT(phone->state == IPC_PHONE_CONNECTING); 223 224 /* Atomic operation */ 225 phone->state = IPC_PHONE_FREE; 225 226 } 226 227 … … 229 230 * All already sent messages will be correctly processed. 230 231 * 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 */ 235 void phone_dealloc(int phoneid) 236 { 237 phone_deallocp(&TASK->phones[phoneid]); 245 238 } 246 239 247 240 /** Connect phone to a given answerbox. 248 241 * 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. 251 244 * @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 */ 251 bool 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); 263 257 } 264 258
Note:
See TracChangeset
for help on using the changeset viewer.