Changes in kernel/generic/src/ipc/ipc.c [287e83f:6aef742] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/ipc/ipc.c
r287e83f r6aef742 62 62 63 63 static slab_cache_t *ipc_call_slab; 64 static slab_cache_t *ipc_answerbox_slab; 64 65 65 66 /** Initialize a call structure. 66 67 * 67 * @param call Call structure to be initialized. 68 * @param call Call structure to be initialized. 69 * 68 70 */ 69 71 static void _ipc_call_init(call_t *call) … … 76 78 77 79 /** Allocate and initialize a call structure. 78 * 80 * 79 81 * The call is initialized, so that the reply will be directed to 80 82 * TASK->answerbox. 81 83 * 82 * @param flags Parameters for slab_alloc (e.g FRAME_ATOMIC). 83 * 84 * @return If flags permit it, return NULL, or initialized kernel 85 * call structure. 86 */ 87 call_t *ipc_call_alloc(int flags) 88 { 89 call_t *call; 90 91 call = slab_alloc(ipc_call_slab, flags); 84 * @param flags Parameters for slab_alloc (e.g FRAME_ATOMIC). 85 * 86 * @return If flags permit it, return NULL, or initialized kernel 87 * call structure. 88 * 89 */ 90 call_t *ipc_call_alloc(unsigned int flags) 91 { 92 call_t *call = slab_alloc(ipc_call_slab, flags); 92 93 if (call) 93 94 _ipc_call_init(call); 94 95 95 96 return call; 96 97 } 97 98 98 /** Initialize a statically allocated call structure.99 *100 * @param call Statically allocated kernel call structure to be101 * initialized.102 */103 void ipc_call_static_init(call_t *call)104 {105 _ipc_call_init(call);106 call->flags |= IPC_CALL_STATIC_ALLOC;107 }108 109 99 /** Deallocate a call structure. 110 100 * 111 * @param call Call structure to be freed. 101 * @param call Call structure to be freed. 102 * 112 103 */ 113 104 void ipc_call_free(call_t *call) 114 105 { 115 ASSERT(!(call->flags & IPC_CALL_STATIC_ALLOC));116 106 /* Check to see if we have data in the IPC_M_DATA_SEND buffer. */ 117 107 if (call->buffer) … … 122 112 /** Initialize an answerbox structure. 123 113 * 124 * @param box Answerbox structure to be initialized. 125 * @param task Task to which the answerbox belongs. 114 * @param box Answerbox structure to be initialized. 115 * @param task Task to which the answerbox belongs. 116 * 126 117 */ 127 118 void ipc_answerbox_init(answerbox_t *box, task_t *task) 128 119 { 129 spinlock_initialize(&box->lock, "ipc_box_lock");130 spinlock_initialize(&box->irq_lock, "ipc_box_irqlock");120 irq_spinlock_initialize(&box->lock, "ipc.box.lock"); 121 irq_spinlock_initialize(&box->irq_lock, "ipc.box.irqlock"); 131 122 waitq_initialize(&box->wq); 123 link_initialize(&box->sync_box_link); 132 124 list_initialize(&box->connected_phones); 133 125 list_initialize(&box->calls); … … 141 133 /** Connect a phone to an answerbox. 142 134 * 143 * @param phone Initialized phone structure. 144 * @param box Initialized answerbox structure. 135 * @param phone Initialized phone structure. 136 * @param box Initialized answerbox structure. 137 * 145 138 */ 146 139 void ipc_phone_connect(phone_t *phone, answerbox_t *box) 147 140 { 148 141 mutex_lock(&phone->lock); 149 142 150 143 phone->state = IPC_PHONE_CONNECTED; 151 144 phone->callee = box; 152 153 spinlock_lock(&box->lock);145 146 irq_spinlock_lock(&box->lock, true); 154 147 list_append(&phone->link, &box->connected_phones); 155 spinlock_unlock(&box->lock);156 148 irq_spinlock_unlock(&box->lock, true); 149 157 150 mutex_unlock(&phone->lock); 158 151 } … … 160 153 /** Initialize a phone structure. 161 154 * 162 * @param phone Phone structure to be initialized. 155 * @param phone Phone structure to be initialized. 156 * 163 157 */ 164 158 void ipc_phone_init(phone_t *phone) … … 172 166 /** Helper function to facilitate synchronous calls. 173 167 * 174 * @param phone Destination kernel phone structure. 175 * @param request Call structure with request. 176 * 177 * @return EOK on success or EINTR if the sleep was interrupted. 168 * @param phone Destination kernel phone structure. 169 * @param request Call structure with request. 170 * 171 * @return EOK on success or EINTR if the sleep was interrupted. 172 * 178 173 */ 179 174 int ipc_call_sync(phone_t *phone, call_t *request) 180 175 { 181 answerbox_t sync_box; 182 183 ipc_answerbox_init(&sync_box, TASK); 184 176 answerbox_t *sync_box = slab_alloc(ipc_answerbox_slab, 0); 177 ipc_answerbox_init(sync_box, TASK); 178 179 /* 180 * Put the answerbox on the TASK's list of synchronous answerboxes so 181 * that it can be cleaned up if the call is interrupted. 182 */ 183 irq_spinlock_lock(&TASK->lock, true); 184 list_append(&sync_box->sync_box_link, &TASK->sync_box_head); 185 irq_spinlock_unlock(&TASK->lock, true); 186 185 187 /* We will receive data in a special box. */ 186 request->callerbox = &sync_box;187 188 request->callerbox = sync_box; 189 188 190 ipc_call(phone, request); 189 if (!ipc_wait_for_call(&sync_box, SYNCH_NO_TIMEOUT, 190 SYNCH_FLAGS_INTERRUPTIBLE)) 191 if (!ipc_wait_for_call(sync_box, SYNCH_NO_TIMEOUT, 192 SYNCH_FLAGS_INTERRUPTIBLE)) { 193 /* The answerbox and the call will be freed by ipc_cleanup(). */ 191 194 return EINTR; 195 } 196 197 /* 198 * The answer arrived without interruption so we can remove the 199 * answerbox from the TASK's list of synchronous answerboxes. 200 */ 201 irq_spinlock_lock(&TASK->lock, true); 202 list_remove(&sync_box->sync_box_link); 203 irq_spinlock_unlock(&TASK->lock, true); 204 205 slab_free(ipc_answerbox_slab, sync_box); 192 206 return EOK; 193 207 } … … 195 209 /** Answer a message which was not dispatched and is not listed in any queue. 196 210 * 197 * @param call Call structure to be answered. 198 */ 199 static void _ipc_answer_free_call(call_t *call) 211 * @param call Call structure to be answered. 212 * @param selflocked If true, then TASK->answebox is locked. 213 * 214 */ 215 static void _ipc_answer_free_call(call_t *call, bool selflocked) 200 216 { 201 217 answerbox_t *callerbox = call->callerbox; 202 218 bool do_lock = ((!selflocked) || callerbox != (&TASK->answerbox)); 219 220 /* Count sent answer */ 221 irq_spinlock_lock(&TASK->lock, true); 222 TASK->ipc_info.answer_sent++; 223 irq_spinlock_unlock(&TASK->lock, true); 224 203 225 call->flags |= IPC_CALL_ANSWERED; 204 226 205 227 if (call->flags & IPC_CALL_FORWARDED) { 206 228 if (call->caller_phone) { … … 209 231 } 210 232 } 211 212 spinlock_lock(&callerbox->lock); 233 234 if (do_lock) 235 irq_spinlock_lock(&callerbox->lock, true); 236 213 237 list_append(&call->link, &callerbox->answers); 214 spinlock_unlock(&callerbox->lock); 238 239 if (do_lock) 240 irq_spinlock_unlock(&callerbox->lock, true); 241 215 242 waitq_wakeup(&callerbox->wq, WAKEUP_FIRST); 216 243 } … … 218 245 /** Answer a message which is in a callee queue. 219 246 * 220 * @param box Answerbox that is answering the message. 221 * @param call Modified request that is being sent back. 247 * @param box Answerbox that is answering the message. 248 * @param call Modified request that is being sent back. 249 * 222 250 */ 223 251 void ipc_answer(answerbox_t *box, call_t *call) 224 252 { 225 253 /* Remove from active box */ 226 spinlock_lock(&box->lock);254 irq_spinlock_lock(&box->lock, true); 227 255 list_remove(&call->link); 228 spinlock_unlock(&box->lock); 256 irq_spinlock_unlock(&box->lock, true); 257 229 258 /* Send back answer */ 230 _ipc_answer_free_call(call );259 _ipc_answer_free_call(call, false); 231 260 } 232 261 … … 236 265 * message and sending it as a normal answer. 237 266 * 238 * @param phone Phone structure the call should appear to come from. 239 * @param call Call structure to be answered. 240 * @param err Return value to be used for the answer. 241 */ 242 void ipc_backsend_err(phone_t *phone, call_t *call, unative_t err) 267 * @param phone Phone structure the call should appear to come from. 268 * @param call Call structure to be answered. 269 * @param err Return value to be used for the answer. 270 * 271 */ 272 void ipc_backsend_err(phone_t *phone, call_t *call, sysarg_t err) 243 273 { 244 274 call->data.phone = phone; 245 275 atomic_inc(&phone->active_calls); 246 276 IPC_SET_RETVAL(call->data, err); 247 _ipc_answer_free_call(call );277 _ipc_answer_free_call(call, false); 248 278 } 249 279 250 280 /** Unsafe unchecking version of ipc_call. 251 281 * 252 * @param phone Phone structure the call comes from. 253 * @param box Destination answerbox structure. 254 * @param call Call structure with request. 282 * @param phone Phone structure the call comes from. 283 * @param box Destination answerbox structure. 284 * @param call Call structure with request. 285 * 255 286 */ 256 287 static void _ipc_call(phone_t *phone, answerbox_t *box, call_t *call) 257 288 { 289 /* Count sent ipc call */ 290 irq_spinlock_lock(&TASK->lock, true); 291 TASK->ipc_info.call_sent++; 292 irq_spinlock_unlock(&TASK->lock, true); 293 258 294 if (!(call->flags & IPC_CALL_FORWARDED)) { 259 295 atomic_inc(&phone->active_calls); 260 296 call->data.phone = phone; 261 } 262 263 spinlock_lock(&box->lock); 297 call->data.task = TASK; 298 } 299 300 irq_spinlock_lock(&box->lock, true); 264 301 list_append(&call->link, &box->calls); 265 spinlock_unlock(&box->lock); 302 irq_spinlock_unlock(&box->lock, true); 303 266 304 waitq_wakeup(&box->wq, WAKEUP_FIRST); 267 305 } … … 269 307 /** Send an asynchronous request using a phone to an answerbox. 270 308 * 271 * @param phone Phone structure the call comes from and which is 272 * connected to the destination answerbox. 273 * @param call Call structure with request. 274 * 275 * @return Return 0 on success, ENOENT on error. 309 * @param phone Phone structure the call comes from and which is 310 * connected to the destination answerbox. 311 * @param call Call structure with request. 312 * 313 * @return Return 0 on success, ENOENT on error. 314 * 276 315 */ 277 316 int ipc_call(phone_t *phone, call_t *call) 278 317 { 279 answerbox_t *box;280 281 318 mutex_lock(&phone->lock); 282 319 if (phone->state != IPC_PHONE_CONNECTED) { … … 284 321 if (call->flags & IPC_CALL_FORWARDED) { 285 322 IPC_SET_RETVAL(call->data, EFORWARD); 286 _ipc_answer_free_call(call );323 _ipc_answer_free_call(call, false); 287 324 } else { 288 325 if (phone->state == IPC_PHONE_HUNGUP) … … 291 328 ipc_backsend_err(phone, call, ENOENT); 292 329 } 330 293 331 return ENOENT; 294 332 } 295 box = phone->callee; 333 334 answerbox_t *box = phone->callee; 296 335 _ipc_call(phone, box, call); 297 336 … … 305 344 * lazily later. 306 345 * 307 * @param phone Phone structure to be hung up. 308 * 309 * @return Return 0 if the phone is disconnected. 310 * Return -1 if the phone was already disconnected. 346 * @param phone Phone structure to be hung up. 347 * 348 * @return 0 if the phone is disconnected. 349 * @return -1 if the phone was already disconnected. 350 * 311 351 */ 312 352 int ipc_phone_hangup(phone_t *phone) 313 353 { 314 answerbox_t *box;315 call_t *call;316 317 354 mutex_lock(&phone->lock); 318 355 if (phone->state == IPC_PHONE_FREE || … … 322 359 return -1; 323 360 } 324 box = phone->callee; 361 362 answerbox_t *box = phone->callee; 325 363 if (phone->state != IPC_PHONE_SLAMMED) { 326 364 /* Remove myself from answerbox */ 327 spinlock_lock(&box->lock);365 irq_spinlock_lock(&box->lock, true); 328 366 list_remove(&phone->link); 329 spinlock_unlock(&box->lock);330 331 call = ipc_call_alloc(0);332 IPC_SET_ METHOD(call->data, IPC_M_PHONE_HUNGUP);367 irq_spinlock_unlock(&box->lock, true); 368 369 call_t *call = ipc_call_alloc(0); 370 IPC_SET_IMETHOD(call->data, IPC_M_PHONE_HUNGUP); 333 371 call->flags |= IPC_CALL_DISCARD_ANSWER; 334 372 _ipc_call(phone, box, call); 335 373 } 336 374 337 375 phone->state = IPC_PHONE_HUNGUP; 338 376 mutex_unlock(&phone->lock); 339 377 340 378 return 0; 341 379 } … … 343 381 /** Forwards call from one answerbox to another one. 344 382 * 345 * @param call 346 * @param newphone 347 * @param oldbox 348 * @param mode 349 * 350 * @return Return0 if forwarding succeeded or an error code if351 * there waserror.352 * 383 * @param call Call structure to be redirected. 384 * @param newphone Phone structure to target answerbox. 385 * @param oldbox Old answerbox structure. 386 * @param mode Flags that specify mode of the forward operation. 387 * 388 * @return 0 if forwarding succeeded or an error code if 389 * there was an error. 390 * 353 391 * The return value serves only as an information for the forwarder, 354 392 * the original caller is notified automatically with EFORWARD. 355 */ 356 int ipc_forward(call_t *call, phone_t *newphone, answerbox_t *oldbox, int mode) 357 { 358 spinlock_lock(&oldbox->lock); 393 * 394 */ 395 int ipc_forward(call_t *call, phone_t *newphone, answerbox_t *oldbox, 396 unsigned int mode) 397 { 398 /* Count forwarded calls */ 399 irq_spinlock_lock(&TASK->lock, true); 400 TASK->ipc_info.forwarded++; 401 irq_spinlock_pass(&TASK->lock, &oldbox->lock); 359 402 list_remove(&call->link); 360 spinlock_unlock(&oldbox->lock);361 403 irq_spinlock_unlock(&oldbox->lock, true); 404 362 405 if (mode & IPC_FF_ROUTE_FROM_ME) { 363 406 if (!call->caller_phone) 364 407 call->caller_phone = call->data.phone; 365 408 call->data.phone = newphone; 366 } 367 409 call->data.task = TASK; 410 } 411 368 412 return ipc_call(newphone, call); 369 413 } … … 372 416 /** Wait for a phone call. 373 417 * 374 * @param box Answerbox expecting the call. 375 * @param usec Timeout in microseconds. See documentation for 376 * waitq_sleep_timeout() for decription of its special 377 * meaning. 378 * @param flags Select mode of sleep operation. See documentation for 379 * waitq_sleep_timeout() for description of its special 380 * meaning. 381 * @return Recived call structure or NULL. 382 * 418 * @param box Answerbox expecting the call. 419 * @param usec Timeout in microseconds. See documentation for 420 * waitq_sleep_timeout() for decription of its special 421 * meaning. 422 * @param flags Select mode of sleep operation. See documentation for 423 * waitq_sleep_timeout() for description of its special 424 * meaning. 425 * 426 * @return Recived call structure or NULL. 427 * 383 428 * To distinguish between a call and an answer, have a look at call->flags. 384 */ 385 call_t *ipc_wait_for_call(answerbox_t *box, uint32_t usec, int flags) 429 * 430 */ 431 call_t *ipc_wait_for_call(answerbox_t *box, uint32_t usec, unsigned int flags) 386 432 { 387 433 call_t *request; 388 ipl_t ipl; 434 uint64_t irq_cnt = 0; 435 uint64_t answer_cnt = 0; 436 uint64_t call_cnt = 0; 389 437 int rc; 390 438 391 439 restart: 392 440 rc = waitq_sleep_timeout(&box->wq, usec, flags); … … 394 442 return NULL; 395 443 396 spinlock_lock(&box->lock);444 irq_spinlock_lock(&box->lock, true); 397 445 if (!list_empty(&box->irq_notifs)) { 398 ipl = interrupts_disable(); 399 spinlock_lock(&box->irq_lock); 400 446 /* Count received IRQ notification */ 447 irq_cnt++; 448 449 irq_spinlock_lock(&box->irq_lock, false); 450 401 451 request = list_get_instance(box->irq_notifs.next, call_t, link); 402 452 list_remove(&request->link); 403 404 spinlock_unlock(&box->irq_lock); 405 interrupts_restore(ipl); 453 454 irq_spinlock_unlock(&box->irq_lock, false); 406 455 } else if (!list_empty(&box->answers)) { 456 /* Count received answer */ 457 answer_cnt++; 458 407 459 /* Handle asynchronous answers */ 408 460 request = list_get_instance(box->answers.next, call_t, link); … … 410 462 atomic_dec(&request->data.phone->active_calls); 411 463 } else if (!list_empty(&box->calls)) { 464 /* Count received call */ 465 call_cnt++; 466 412 467 /* Handle requests */ 413 468 request = list_get_instance(box->calls.next, call_t, link); 414 469 list_remove(&request->link); 470 415 471 /* Append request to dispatch queue */ 416 472 list_append(&request->link, &box->dispatched_calls); 417 473 } else { 418 474 /* This can happen regularly after ipc_cleanup */ 419 spinlock_unlock(&box->lock);475 irq_spinlock_unlock(&box->lock, true); 420 476 goto restart; 421 477 } 422 spinlock_unlock(&box->lock); 478 479 irq_spinlock_pass(&box->lock, &TASK->lock); 480 481 TASK->ipc_info.irq_notif_received += irq_cnt; 482 TASK->ipc_info.answer_received += answer_cnt; 483 TASK->ipc_info.call_received += call_cnt; 484 485 irq_spinlock_unlock(&TASK->lock, true); 486 423 487 return request; 424 488 } … … 426 490 /** Answer all calls from list with EHANGUP answer. 427 491 * 428 * @param lst Head of the list to be cleaned up. 492 * @param lst Head of the list to be cleaned up. 493 * 429 494 */ 430 495 void ipc_cleanup_call_list(link_t *lst) 431 496 { 432 call_t *call;433 434 497 while (!list_empty(lst)) { 435 call = list_get_instance(lst->next, call_t, link);498 call_t *call = list_get_instance(lst->next, call_t, link); 436 499 if (call->buffer) 437 500 free(call->buffer); 501 438 502 list_remove(&call->link); 439 503 440 504 IPC_SET_RETVAL(call->data, EHANGUP); 441 _ipc_answer_free_call(call );505 _ipc_answer_free_call(call, true); 442 506 } 443 507 } … … 445 509 /** Disconnects all phones connected to an answerbox. 446 510 * 447 * @param box Answerbox to disconnect phones from. 448 * @param notify_box If true, the answerbox will get a hangup message for 449 * each disconnected phone. 511 * @param box Answerbox to disconnect phones from. 512 * @param notify_box If true, the answerbox will get a hangup message for 513 * each disconnected phone. 514 * 450 515 */ 451 516 void ipc_answerbox_slam_phones(answerbox_t *box, bool notify_box) … … 453 518 phone_t *phone; 454 519 DEADLOCK_PROBE_INIT(p_phonelck); 455 ipl_t ipl; 456 call_t *call; 457 458 call = notify_box ? ipc_call_alloc(0) : NULL; 459 520 521 call_t *call = notify_box ? ipc_call_alloc(0) : NULL; 522 460 523 /* Disconnect all phones connected to our answerbox */ 461 524 restart_phones: 462 ipl = interrupts_disable(); 463 spinlock_lock(&box->lock); 525 irq_spinlock_lock(&box->lock, true); 464 526 while (!list_empty(&box->connected_phones)) { 465 527 phone = list_get_instance(box->connected_phones.next, 466 528 phone_t, link); 467 529 if (SYNCH_FAILED(mutex_trylock(&phone->lock))) { 468 spinlock_unlock(&box->lock); 469 interrupts_restore(ipl); 530 irq_spinlock_unlock(&box->lock, true); 470 531 DEADLOCK_PROBE(p_phonelck, DEADLOCK_THRESHOLD); 471 532 goto restart_phones; … … 474 535 /* Disconnect phone */ 475 536 ASSERT(phone->state == IPC_PHONE_CONNECTED); 476 537 477 538 list_remove(&phone->link); 478 539 phone->state = IPC_PHONE_SLAMMED; 479 540 480 541 if (notify_box) { 481 542 mutex_unlock(&phone->lock); 482 spinlock_unlock(&box->lock); 483 interrupts_restore(ipl); 484 543 irq_spinlock_unlock(&box->lock, true); 544 485 545 /* 486 546 * Send one message to the answerbox for each … … 489 549 * disconnected. 490 550 */ 491 IPC_SET_ METHOD(call->data, IPC_M_PHONE_HUNGUP);551 IPC_SET_IMETHOD(call->data, IPC_M_PHONE_HUNGUP); 492 552 call->flags |= IPC_CALL_DISCARD_ANSWER; 493 553 _ipc_call(phone, box, call); 494 554 495 555 /* Allocate another call in advance */ 496 556 call = ipc_call_alloc(0); 497 557 498 558 /* Must start again */ 499 559 goto restart_phones; 500 560 } 501 561 502 562 mutex_unlock(&phone->lock); 503 563 } 504 505 spinlock_unlock(&box->lock); 506 interrupts_restore(ipl); 507 564 565 irq_spinlock_unlock(&box->lock, true); 566 508 567 /* Free unused call */ 509 568 if (call) … … 511 570 } 512 571 513 /** Clean sup all IPC communication of the current task.572 /** Clean up all IPC communication of the current task. 514 573 * 515 574 * Note: ipc_hangup sets returning answerbox to TASK->answerbox, you 516 575 * have to change it as well if you want to cleanup other tasks than TASK. 576 * 517 577 */ 518 578 void ipc_cleanup(void) 519 579 { 520 int i;521 call_t *call;522 523 580 /* Disconnect all our phones ('ipc_phone_hangup') */ 581 size_t i; 524 582 for (i = 0; i < IPC_MAX_PHONES; i++) 525 583 ipc_phone_hangup(&TASK->phones[i]); 526 584 527 585 /* Unsubscribe from any event notifications. */ 528 586 event_cleanup_answerbox(&TASK->answerbox); 529 587 530 588 /* Disconnect all connected irqs */ 531 589 ipc_irq_cleanup(&TASK->answerbox); 532 590 533 591 /* Disconnect all phones connected to our regular answerbox */ 534 592 ipc_answerbox_slam_phones(&TASK->answerbox, false); 535 593 536 594 #ifdef CONFIG_UDEBUG 537 595 /* Clean up kbox thread and communications */ 538 596 ipc_kbox_cleanup(); 539 597 #endif 540 598 541 599 /* Answer all messages in 'calls' and 'dispatched_calls' queues */ 542 spinlock_lock(&TASK->answerbox.lock);600 irq_spinlock_lock(&TASK->answerbox.lock, true); 543 601 ipc_cleanup_call_list(&TASK->answerbox.dispatched_calls); 544 602 ipc_cleanup_call_list(&TASK->answerbox.calls); 545 spinlock_unlock(&TASK->answerbox.lock); 546 547 /* Wait for all async answers to arrive */ 548 while (1) { 549 /* Go through all phones, until all are FREE... */ 550 /* Locking not needed, no one else should modify 551 * it, when we are in cleanup */ 603 irq_spinlock_unlock(&TASK->answerbox.lock, true); 604 605 /* Wait for all answers to interrupted synchronous calls to arrive */ 606 ipl_t ipl = interrupts_disable(); 607 while (!list_empty(&TASK->sync_box_head)) { 608 answerbox_t *box = list_get_instance(TASK->sync_box_head.next, 609 answerbox_t, sync_box_link); 610 611 list_remove(&box->sync_box_link); 612 call_t *call = ipc_wait_for_call(box, SYNCH_NO_TIMEOUT, 613 SYNCH_FLAGS_NONE); 614 ipc_call_free(call); 615 slab_free(ipc_answerbox_slab, box); 616 } 617 interrupts_restore(ipl); 618 619 /* Wait for all answers to asynchronous calls to arrive */ 620 while (true) { 621 /* 622 * Go through all phones, until they are all FREE 623 * Locking is not needed, no one else should modify 624 * it when we are in cleanup 625 */ 552 626 for (i = 0; i < IPC_MAX_PHONES; i++) { 553 627 if (TASK->phones[i].state == IPC_PHONE_HUNGUP && 554 atomic_get(&TASK->phones[i].active_calls) == 0) 628 atomic_get(&TASK->phones[i].active_calls) == 0) { 555 629 TASK->phones[i].state = IPC_PHONE_FREE; 630 TASK->phones[i].callee = NULL; 631 } 556 632 557 /* Just for sure, we might have had some 558 * IPC_PHONE_CONNECTING phones */ 633 /* 634 * Just for sure, we might have had some 635 * IPC_PHONE_CONNECTING phones 636 */ 559 637 if (TASK->phones[i].state == IPC_PHONE_CONNECTED) 560 638 ipc_phone_hangup(&TASK->phones[i]); 561 /* If the hangup succeeded, it has sent a HANGUP 639 640 /* 641 * If the hangup succeeded, it has sent a HANGUP 562 642 * message, the IPC is now in HUNGUP state, we 563 * wait for the reply to come */ 643 * wait for the reply to come 644 */ 564 645 565 646 if (TASK->phones[i].state != IPC_PHONE_FREE) 566 647 break; 567 648 } 568 /* Voila, got into cleanup */ 649 650 /* Got into cleanup */ 569 651 if (i == IPC_MAX_PHONES) 570 652 break; 571 653 572 call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT,654 call_t *call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT, 573 655 SYNCH_FLAGS_NONE); 574 656 ASSERT((call->flags & IPC_CALL_ANSWERED) || 575 657 (call->flags & IPC_CALL_NOTIF)); 576 ASSERT(!(call->flags & IPC_CALL_STATIC_ALLOC)); 577 578 /* 579 * Record the receipt of this call in the current task's counter 580 * of active calls. IPC_M_PHONE_HUNGUP calls do not contribute 581 * to this counter so do not record answers to them either. 582 */ 583 if (!(call->flags & IPC_CALL_DISCARD_ANSWER)) 584 atomic_dec(&TASK->active_calls); 658 585 659 ipc_call_free(call); 586 660 } 587 661 } 588 662 589 590 /** Initilize IPC subsystem */ 663 /** Initilize IPC subsystem 664 * 665 */ 591 666 void ipc_init(void) 592 667 { 593 668 ipc_call_slab = slab_cache_create("ipc_call", sizeof(call_t), 0, NULL, 594 669 NULL, 0); 595 } 596 670 ipc_answerbox_slab = slab_cache_create("ipc_answerbox", 671 sizeof(answerbox_t), 0, NULL, NULL, 0); 672 } 597 673 598 674 /** List answerbox contents. 599 675 * 600 * @param taskid Task ID. 676 * @param taskid Task ID. 677 * 601 678 */ 602 679 void ipc_print_task(task_id_t taskid) 603 680 { 604 task_t *task; 605 int i; 606 call_t *call; 607 link_t *tmp; 608 609 spinlock_lock(&tasks_lock); 610 task = task_find_by_id(taskid); 611 if (task) 612 spinlock_lock(&task->lock); 613 spinlock_unlock(&tasks_lock); 614 if (!task) 681 irq_spinlock_lock(&tasks_lock, true); 682 task_t *task = task_find_by_id(taskid); 683 684 if (!task) { 685 irq_spinlock_unlock(&tasks_lock, true); 615 686 return; 616 617 /* Print opened phones & details */ 618 printf("PHONE:\n"); 687 } 688 689 /* Hand-over-hand locking */ 690 irq_spinlock_exchange(&tasks_lock, &task->lock); 691 692 printf("[phone id] [calls] [state\n"); 693 694 size_t i; 619 695 for (i = 0; i < IPC_MAX_PHONES; i++) { 620 696 if (SYNCH_FAILED(mutex_trylock(&task->phones[i].lock))) { 621 printf("% d: mutex busy\n", i);697 printf("%-10zu (mutex busy)\n", i); 622 698 continue; 623 699 } 700 624 701 if (task->phones[i].state != IPC_PHONE_FREE) { 625 printf("%d: ", i); 702 printf("%-10zu %7" PRIun " ", i, 703 atomic_get(&task->phones[i].active_calls)); 704 626 705 switch (task->phones[i].state) { 627 706 case IPC_PHONE_CONNECTING: 628 printf("connecting 707 printf("connecting"); 629 708 break; 630 709 case IPC_PHONE_CONNECTED: 631 printf("connected to: %p ", 632 task->phones[i].callee); 710 printf("connected to %" PRIu64 " (%s)", 711 task->phones[i].callee->task->taskid, 712 task->phones[i].callee->task->name); 633 713 break; 634 714 case IPC_PHONE_SLAMMED: 635 printf("slammed by : %p ",636 715 printf("slammed by %p", 716 task->phones[i].callee); 637 717 break; 638 718 case IPC_PHONE_HUNGUP: 639 printf("hung up - was: %p ",640 719 printf("hung up by %p", 720 task->phones[i].callee); 641 721 break; 642 722 default: 643 723 break; 644 724 } 645 printf("active: %ld\n",646 atomic_get(&task->phones[i].active_calls));725 726 printf("\n"); 647 727 } 728 648 729 mutex_unlock(&task->phones[i].lock); 649 730 } 650 651 652 /* Print answerbox - calls */ 653 spinlock_lock(&task->answerbox.lock); 654 printf("ABOX - CALLS:\n"); 655 for (tmp = task->answerbox.calls.next; tmp != &task->answerbox.calls; 656 tmp = tmp->next) { 657 call = list_get_instance(tmp, call_t, link); 658 printf("Callid: %p Srctask:%" PRIu64 " M:%" PRIun 659 " A1:%" PRIun " A2:%" PRIun " A3:%" PRIun 660 " A4:%" PRIun " A5:%" PRIun " Flags:%x\n", call, 661 call->sender->taskid, 662 IPC_GET_METHOD(call->data), IPC_GET_ARG1(call->data), 731 732 irq_spinlock_lock(&task->answerbox.lock, false); 733 734 #ifdef __32_BITS__ 735 printf("[call id ] [method] [arg1] [arg2] [arg3] [arg4] [arg5]" 736 " [flags] [sender\n"); 737 #endif 738 739 #ifdef __64_BITS__ 740 printf("[call id ] [method] [arg1] [arg2] [arg3] [arg4]" 741 " [arg5] [flags] [sender\n"); 742 #endif 743 744 link_t *cur; 745 746 printf(" --- incomming calls ---\n"); 747 for (cur = task->answerbox.calls.next; cur != &task->answerbox.calls; 748 cur = cur->next) { 749 call_t *call = list_get_instance(cur, call_t, link); 750 751 #ifdef __32_BITS__ 752 printf("%10p ", call); 753 #endif 754 755 #ifdef __64_BITS__ 756 printf("%18p ", call); 757 #endif 758 759 printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun 760 " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n", 761 IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data), 663 762 IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data), 664 763 IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data), 665 call->flags); 666 } 667 /* Print answerbox - calls */ 668 printf("ABOX - DISPATCHED CALLS:\n"); 669 for (tmp = task->answerbox.dispatched_calls.next; 670 tmp != &task->answerbox.dispatched_calls; 671 tmp = tmp->next) { 672 call = list_get_instance(tmp, call_t, link); 673 printf("Callid: %p Srctask:%" PRIu64 " M:%" PRIun 674 " A1:%" PRIun " A2:%" PRIun " A3:%" PRIun 675 " A4:%" PRIun " A5:%" PRIun " Flags:%x\n", call, 676 call->sender->taskid, 677 IPC_GET_METHOD(call->data), IPC_GET_ARG1(call->data), 764 call->flags, call->sender->taskid, call->sender->name); 765 } 766 767 printf(" --- dispatched calls ---\n"); 768 for (cur = task->answerbox.dispatched_calls.next; 769 cur != &task->answerbox.dispatched_calls; 770 cur = cur->next) { 771 call_t *call = list_get_instance(cur, call_t, link); 772 773 #ifdef __32_BITS__ 774 printf("%10p ", call); 775 #endif 776 777 #ifdef __64_BITS__ 778 printf("%18p ", call); 779 #endif 780 781 printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun 782 " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n", 783 IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data), 678 784 IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data), 679 785 IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data), 680 call->flags); 681 } 682 /* Print answerbox - calls */ 683 printf("ABOX - ANSWERS:\n"); 684 for (tmp = task->answerbox.answers.next; 685 tmp != &task->answerbox.answers; 686 tmp = tmp->next) { 687 call = list_get_instance(tmp, call_t, link); 688 printf("Callid:%p M:%" PRIun " A1:%" PRIun " A2:%" PRIun 689 " A3:%" PRIun " A4:%" PRIun " A5:%" PRIun " Flags:%x\n", 690 call, IPC_GET_METHOD(call->data), IPC_GET_ARG1(call->data), 786 call->flags, call->sender->taskid, call->sender->name); 787 } 788 789 printf(" --- incoming answers ---\n"); 790 for (cur = task->answerbox.answers.next; 791 cur != &task->answerbox.answers; 792 cur = cur->next) { 793 call_t *call = list_get_instance(cur, call_t, link); 794 795 #ifdef __32_BITS__ 796 printf("%10p ", call); 797 #endif 798 799 #ifdef __64_BITS__ 800 printf("%18p ", call); 801 #endif 802 803 printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun 804 " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n", 805 IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data), 691 806 IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data), 692 807 IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data), 693 call->flags );694 } 695 696 spinlock_unlock(&task->answerbox.lock);697 spinlock_unlock(&task->lock);808 call->flags, call->sender->taskid, call->sender->name); 809 } 810 811 irq_spinlock_unlock(&task->answerbox.lock, false); 812 irq_spinlock_unlock(&task->lock, true); 698 813 } 699 814
Note:
See TracChangeset
for help on using the changeset viewer.