Changeset 46c20c8 in mainline for kernel/generic/src/ipc
- Timestamp:
- 2010-11-26T20:08:10Z (15 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 45df59a
- Parents:
- fb150d78 (diff), ffdd2b9 (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. - Location:
- kernel/generic/src/ipc
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/ipc/event.c
rfb150d78 r46c20c8 38 38 #include <ipc/event_types.h> 39 39 #include <mm/slab.h> 40 #include < arch/types.h>40 #include <typedefs.h> 41 41 #include <synch/spinlock.h> 42 42 #include <console/console.h> … … 137 137 IPC_SET_ARG5(call->data, a5); 138 138 139 ipl_t ipl = interrupts_disable(); 140 spinlock_lock(&events[evno].answerbox->irq_lock); 139 irq_spinlock_lock(&events[evno].answerbox->irq_lock, true); 141 140 list_append(&call->link, &events[evno].answerbox->irq_notifs); 142 spinlock_unlock(&events[evno].answerbox->irq_lock); 143 interrupts_restore(ipl); 141 irq_spinlock_unlock(&events[evno].answerbox->irq_lock, true); 144 142 145 143 waitq_wakeup(&events[evno].answerbox->wq, WAKEUP_FIRST); -
kernel/generic/src/ipc/ipc.c
rfb150d78 r46c20c8 66 66 /** Initialize a call structure. 67 67 * 68 * @param call Call structure to be initialized. 68 * @param call Call structure to be initialized. 69 * 69 70 */ 70 71 static void _ipc_call_init(call_t *call) … … 77 78 78 79 /** Allocate and initialize a call structure. 79 * 80 * 80 81 * The call is initialized, so that the reply will be directed to 81 82 * TASK->answerbox. 82 83 * 83 * @param flags Parameters for slab_alloc (e.g FRAME_ATOMIC). 84 * 85 * @return If flags permit it, return NULL, or initialized kernel 86 * call structure. 87 */ 88 call_t *ipc_call_alloc(int flags) 89 { 90 call_t *call; 91 92 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); 93 93 if (call) 94 94 _ipc_call_init(call); 95 95 96 96 return call; 97 97 } … … 99 99 /** Deallocate a call structure. 100 100 * 101 * @param call Call structure to be freed. 101 * @param call Call structure to be freed. 102 * 102 103 */ 103 104 void ipc_call_free(call_t *call) … … 111 112 /** Initialize an answerbox structure. 112 113 * 113 * @param box Answerbox structure to be initialized. 114 * @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 * 115 117 */ 116 118 void ipc_answerbox_init(answerbox_t *box, task_t *task) 117 119 { 118 spinlock_initialize(&box->lock, "ipc_box_lock");119 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"); 120 122 waitq_initialize(&box->wq); 121 123 link_initialize(&box->sync_box_link); … … 131 133 /** Connect a phone to an answerbox. 132 134 * 133 * @param phone Initialized phone structure. 134 * @param box Initialized answerbox structure. 135 * @param phone Initialized phone structure. 136 * @param box Initialized answerbox structure. 137 * 135 138 */ 136 139 void ipc_phone_connect(phone_t *phone, answerbox_t *box) 137 140 { 138 141 mutex_lock(&phone->lock); 139 142 140 143 phone->state = IPC_PHONE_CONNECTED; 141 144 phone->callee = box; 142 143 spinlock_lock(&box->lock);145 146 irq_spinlock_lock(&box->lock, true); 144 147 list_append(&phone->link, &box->connected_phones); 145 spinlock_unlock(&box->lock);146 148 irq_spinlock_unlock(&box->lock, true); 149 147 150 mutex_unlock(&phone->lock); 148 151 } … … 150 153 /** Initialize a phone structure. 151 154 * 152 * @param phone Phone structure to be initialized. 155 * @param phone Phone structure to be initialized. 156 * 153 157 */ 154 158 void ipc_phone_init(phone_t *phone) … … 162 166 /** Helper function to facilitate synchronous calls. 163 167 * 164 * @param phone Destination kernel phone structure. 165 * @param request Call structure with request. 166 * 167 * @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 * 168 173 */ 169 174 int ipc_call_sync(phone_t *phone, call_t *request) 170 175 { 171 answerbox_t *sync_box; 172 ipl_t ipl; 173 174 sync_box = slab_alloc(ipc_answerbox_slab, 0); 176 answerbox_t *sync_box = slab_alloc(ipc_answerbox_slab, 0); 175 177 ipc_answerbox_init(sync_box, TASK); 176 178 177 179 /* 178 180 * Put the answerbox on the TASK's list of synchronous answerboxes so 179 181 * that it can be cleaned up if the call is interrupted. 180 182 */ 181 ipl = interrupts_disable(); 182 spinlock_lock(&TASK->lock); 183 irq_spinlock_lock(&TASK->lock, true); 183 184 list_append(&sync_box->sync_box_link, &TASK->sync_box_head); 184 spinlock_unlock(&TASK->lock); 185 interrupts_restore(ipl); 186 185 irq_spinlock_unlock(&TASK->lock, true); 186 187 187 /* We will receive data in a special box. */ 188 188 request->callerbox = sync_box; 189 189 190 190 ipc_call(phone, request); 191 191 if (!ipc_wait_for_call(sync_box, SYNCH_NO_TIMEOUT, 192 192 SYNCH_FLAGS_INTERRUPTIBLE)) { 193 /* The answerbox and the call will be freed by ipc_cleanup(). */193 /* The answerbox and the call will be freed by ipc_cleanup(). */ 194 194 return EINTR; 195 195 } 196 196 197 197 /* 198 198 * The answer arrived without interruption so we can remove the 199 199 * answerbox from the TASK's list of synchronous answerboxes. 200 200 */ 201 (void) interrupts_disable(); 202 spinlock_lock(&TASK->lock); 201 irq_spinlock_lock(&TASK->lock, true); 203 202 list_remove(&sync_box->sync_box_link); 204 spinlock_unlock(&TASK->lock); 205 interrupts_restore(ipl); 206 203 irq_spinlock_unlock(&TASK->lock, true); 204 207 205 slab_free(ipc_answerbox_slab, sync_box); 208 206 return EOK; … … 211 209 /** Answer a message which was not dispatched and is not listed in any queue. 212 210 * 213 * @param call Call structure to be answered. 214 * @param selflocked If true, then TASK->answebox is locked. 211 * @param call Call structure to be answered. 212 * @param selflocked If true, then TASK->answebox is locked. 213 * 215 214 */ 216 215 static void _ipc_answer_free_call(call_t *call, bool selflocked) … … 218 217 answerbox_t *callerbox = call->callerbox; 219 218 bool do_lock = ((!selflocked) || callerbox != (&TASK->answerbox)); 220 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 221 225 call->flags |= IPC_CALL_ANSWERED; 222 226 223 227 if (call->flags & IPC_CALL_FORWARDED) { 224 228 if (call->caller_phone) { … … 227 231 } 228 232 } 229 233 230 234 if (do_lock) 231 spinlock_lock(&callerbox->lock); 235 irq_spinlock_lock(&callerbox->lock, true); 236 232 237 list_append(&call->link, &callerbox->answers); 238 233 239 if (do_lock) 234 spinlock_unlock(&callerbox->lock); 240 irq_spinlock_unlock(&callerbox->lock, true); 241 235 242 waitq_wakeup(&callerbox->wq, WAKEUP_FIRST); 236 243 } … … 238 245 /** Answer a message which is in a callee queue. 239 246 * 240 * @param box Answerbox that is answering the message. 241 * @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 * 242 250 */ 243 251 void ipc_answer(answerbox_t *box, call_t *call) 244 252 { 245 253 /* Remove from active box */ 246 spinlock_lock(&box->lock);254 irq_spinlock_lock(&box->lock, true); 247 255 list_remove(&call->link); 248 spinlock_unlock(&box->lock); 256 irq_spinlock_unlock(&box->lock, true); 257 249 258 /* Send back answer */ 250 259 _ipc_answer_free_call(call, false); … … 256 265 * message and sending it as a normal answer. 257 266 * 258 * @param phone Phone structure the call should appear to come from. 259 * @param call Call structure to be answered. 260 * @param err Return value to be used for the answer. 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 * 261 271 */ 262 272 void ipc_backsend_err(phone_t *phone, call_t *call, unative_t err) … … 270 280 /** Unsafe unchecking version of ipc_call. 271 281 * 272 * @param phone Phone structure the call comes from. 273 * @param box Destination answerbox structure. 274 * @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 * 275 286 */ 276 287 static void _ipc_call(phone_t *phone, answerbox_t *box, call_t *call) 277 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 278 294 if (!(call->flags & IPC_CALL_FORWARDED)) { 279 295 atomic_inc(&phone->active_calls); 280 296 call->data.phone = phone; 281 297 } 282 283 spinlock_lock(&box->lock);298 299 irq_spinlock_lock(&box->lock, true); 284 300 list_append(&call->link, &box->calls); 285 spinlock_unlock(&box->lock); 301 irq_spinlock_unlock(&box->lock, true); 302 286 303 waitq_wakeup(&box->wq, WAKEUP_FIRST); 287 304 } … … 289 306 /** Send an asynchronous request using a phone to an answerbox. 290 307 * 291 * @param phone Phone structure the call comes from and which is 292 * connected to the destination answerbox. 293 * @param call Call structure with request. 294 * 295 * @return Return 0 on success, ENOENT on error. 308 * @param phone Phone structure the call comes from and which is 309 * connected to the destination answerbox. 310 * @param call Call structure with request. 311 * 312 * @return Return 0 on success, ENOENT on error. 313 * 296 314 */ 297 315 int ipc_call(phone_t *phone, call_t *call) 298 316 { 299 answerbox_t *box;300 301 317 mutex_lock(&phone->lock); 302 318 if (phone->state != IPC_PHONE_CONNECTED) { … … 311 327 ipc_backsend_err(phone, call, ENOENT); 312 328 } 329 313 330 return ENOENT; 314 331 } 315 box = phone->callee; 332 333 answerbox_t *box = phone->callee; 316 334 _ipc_call(phone, box, call); 317 335 … … 325 343 * lazily later. 326 344 * 327 * @param phone Phone structure to be hung up. 328 * 329 * @return Return 0 if the phone is disconnected. 330 * Return -1 if the phone was already disconnected. 345 * @param phone Phone structure to be hung up. 346 * 347 * @return 0 if the phone is disconnected. 348 * @return -1 if the phone was already disconnected. 349 * 331 350 */ 332 351 int ipc_phone_hangup(phone_t *phone) 333 352 { 334 answerbox_t *box;335 call_t *call;336 337 353 mutex_lock(&phone->lock); 338 354 if (phone->state == IPC_PHONE_FREE || … … 342 358 return -1; 343 359 } 344 box = phone->callee; 360 361 answerbox_t *box = phone->callee; 345 362 if (phone->state != IPC_PHONE_SLAMMED) { 346 363 /* Remove myself from answerbox */ 347 spinlock_lock(&box->lock);364 irq_spinlock_lock(&box->lock, true); 348 365 list_remove(&phone->link); 349 spinlock_unlock(&box->lock);350 351 call = ipc_call_alloc(0);366 irq_spinlock_unlock(&box->lock, true); 367 368 call_t *call = ipc_call_alloc(0); 352 369 IPC_SET_METHOD(call->data, IPC_M_PHONE_HUNGUP); 353 370 call->flags |= IPC_CALL_DISCARD_ANSWER; 354 371 _ipc_call(phone, box, call); 355 372 } 356 373 357 374 phone->state = IPC_PHONE_HUNGUP; 358 375 mutex_unlock(&phone->lock); 359 376 360 377 return 0; 361 378 } … … 363 380 /** Forwards call from one answerbox to another one. 364 381 * 365 * @param call Call structure to be redirected.366 * @param newphone Phone structure to target answerbox.367 * @param oldbox Old answerbox structure.368 * @param mode Flags that specify mode of the forward operation.369 * 370 * @return Return0 if forwarding succeeded or an error code if371 * there waserror.372 * 382 * @param call Call structure to be redirected. 383 * @param newphone Phone structure to target answerbox. 384 * @param oldbox Old answerbox structure. 385 * @param mode Flags that specify mode of the forward operation. 386 * 387 * @return 0 if forwarding succeeded or an error code if 388 * there was an error. 389 * 373 390 * The return value serves only as an information for the forwarder, 374 391 * the original caller is notified automatically with EFORWARD. 375 */ 376 int ipc_forward(call_t *call, phone_t *newphone, answerbox_t *oldbox, int mode) 377 { 378 spinlock_lock(&oldbox->lock); 392 * 393 */ 394 int ipc_forward(call_t *call, phone_t *newphone, answerbox_t *oldbox, 395 unsigned int mode) 396 { 397 /* Count forwarded calls */ 398 irq_spinlock_lock(&TASK->lock, true); 399 TASK->ipc_info.forwarded++; 400 irq_spinlock_pass(&TASK->lock, &oldbox->lock); 379 401 list_remove(&call->link); 380 spinlock_unlock(&oldbox->lock);381 402 irq_spinlock_unlock(&oldbox->lock, true); 403 382 404 if (mode & IPC_FF_ROUTE_FROM_ME) { 383 405 if (!call->caller_phone) … … 385 407 call->data.phone = newphone; 386 408 } 387 409 388 410 return ipc_call(newphone, call); 389 411 } … … 392 414 /** Wait for a phone call. 393 415 * 394 * @param box Answerbox expecting the call. 395 * @param usec Timeout in microseconds. See documentation for 396 * waitq_sleep_timeout() for decription of its special 397 * meaning. 398 * @param flags Select mode of sleep operation. See documentation for 399 * waitq_sleep_timeout() for description of its special 400 * meaning. 401 * @return Recived call structure or NULL. 402 * 416 * @param box Answerbox expecting the call. 417 * @param usec Timeout in microseconds. See documentation for 418 * waitq_sleep_timeout() for decription of its special 419 * meaning. 420 * @param flags Select mode of sleep operation. See documentation for 421 * waitq_sleep_timeout() for description of its special 422 * meaning. 423 * 424 * @return Recived call structure or NULL. 425 * 403 426 * To distinguish between a call and an answer, have a look at call->flags. 404 */ 405 call_t *ipc_wait_for_call(answerbox_t *box, uint32_t usec, int flags) 427 * 428 */ 429 call_t *ipc_wait_for_call(answerbox_t *box, uint32_t usec, unsigned int flags) 406 430 { 407 431 call_t *request; 408 ipl_t ipl; 432 uint64_t irq_cnt = 0; 433 uint64_t answer_cnt = 0; 434 uint64_t call_cnt = 0; 409 435 int rc; 410 436 411 437 restart: 412 438 rc = waitq_sleep_timeout(&box->wq, usec, flags); … … 414 440 return NULL; 415 441 416 spinlock_lock(&box->lock);442 irq_spinlock_lock(&box->lock, true); 417 443 if (!list_empty(&box->irq_notifs)) { 418 ipl = interrupts_disable(); 419 spinlock_lock(&box->irq_lock); 420 444 /* Count received IRQ notification */ 445 irq_cnt++; 446 447 irq_spinlock_lock(&box->irq_lock, false); 448 421 449 request = list_get_instance(box->irq_notifs.next, call_t, link); 422 450 list_remove(&request->link); 423 424 spinlock_unlock(&box->irq_lock); 425 interrupts_restore(ipl); 451 452 irq_spinlock_unlock(&box->irq_lock, false); 426 453 } else if (!list_empty(&box->answers)) { 454 /* Count received answer */ 455 answer_cnt++; 456 427 457 /* Handle asynchronous answers */ 428 458 request = list_get_instance(box->answers.next, call_t, link); … … 430 460 atomic_dec(&request->data.phone->active_calls); 431 461 } else if (!list_empty(&box->calls)) { 462 /* Count received call */ 463 call_cnt++; 464 432 465 /* Handle requests */ 433 466 request = list_get_instance(box->calls.next, call_t, link); 434 467 list_remove(&request->link); 468 435 469 /* Append request to dispatch queue */ 436 470 list_append(&request->link, &box->dispatched_calls); 437 471 } else { 438 472 /* This can happen regularly after ipc_cleanup */ 439 spinlock_unlock(&box->lock);473 irq_spinlock_unlock(&box->lock, true); 440 474 goto restart; 441 475 } 442 spinlock_unlock(&box->lock); 476 477 irq_spinlock_pass(&box->lock, &TASK->lock); 478 479 TASK->ipc_info.irq_notif_received += irq_cnt; 480 TASK->ipc_info.answer_received += answer_cnt; 481 TASK->ipc_info.call_received += call_cnt; 482 483 irq_spinlock_unlock(&TASK->lock, true); 484 443 485 return request; 444 486 } … … 446 488 /** Answer all calls from list with EHANGUP answer. 447 489 * 448 * @param lst Head of the list to be cleaned up. 490 * @param lst Head of the list to be cleaned up. 491 * 449 492 */ 450 493 void ipc_cleanup_call_list(link_t *lst) 451 494 { 452 call_t *call;453 454 495 while (!list_empty(lst)) { 455 call = list_get_instance(lst->next, call_t, link);496 call_t *call = list_get_instance(lst->next, call_t, link); 456 497 if (call->buffer) 457 498 free(call->buffer); 499 458 500 list_remove(&call->link); 459 501 460 502 IPC_SET_RETVAL(call->data, EHANGUP); 461 503 _ipc_answer_free_call(call, true); … … 465 507 /** Disconnects all phones connected to an answerbox. 466 508 * 467 * @param box Answerbox to disconnect phones from. 468 * @param notify_box If true, the answerbox will get a hangup message for 469 * each disconnected phone. 509 * @param box Answerbox to disconnect phones from. 510 * @param notify_box If true, the answerbox will get a hangup message for 511 * each disconnected phone. 512 * 470 513 */ 471 514 void ipc_answerbox_slam_phones(answerbox_t *box, bool notify_box) … … 473 516 phone_t *phone; 474 517 DEADLOCK_PROBE_INIT(p_phonelck); 475 ipl_t ipl; 476 call_t *call; 477 478 call = notify_box ? ipc_call_alloc(0) : NULL; 479 518 519 call_t *call = notify_box ? ipc_call_alloc(0) : NULL; 520 480 521 /* Disconnect all phones connected to our answerbox */ 481 522 restart_phones: 482 ipl = interrupts_disable(); 483 spinlock_lock(&box->lock); 523 irq_spinlock_lock(&box->lock, true); 484 524 while (!list_empty(&box->connected_phones)) { 485 525 phone = list_get_instance(box->connected_phones.next, 486 526 phone_t, link); 487 527 if (SYNCH_FAILED(mutex_trylock(&phone->lock))) { 488 spinlock_unlock(&box->lock); 489 interrupts_restore(ipl); 528 irq_spinlock_unlock(&box->lock, true); 490 529 DEADLOCK_PROBE(p_phonelck, DEADLOCK_THRESHOLD); 491 530 goto restart_phones; … … 494 533 /* Disconnect phone */ 495 534 ASSERT(phone->state == IPC_PHONE_CONNECTED); 496 535 497 536 list_remove(&phone->link); 498 537 phone->state = IPC_PHONE_SLAMMED; 499 538 500 539 if (notify_box) { 501 540 mutex_unlock(&phone->lock); 502 spinlock_unlock(&box->lock); 503 interrupts_restore(ipl); 504 541 irq_spinlock_unlock(&box->lock, true); 542 505 543 /* 506 544 * Send one message to the answerbox for each … … 512 550 call->flags |= IPC_CALL_DISCARD_ANSWER; 513 551 _ipc_call(phone, box, call); 514 552 515 553 /* Allocate another call in advance */ 516 554 call = ipc_call_alloc(0); 517 555 518 556 /* Must start again */ 519 557 goto restart_phones; 520 558 } 521 559 522 560 mutex_unlock(&phone->lock); 523 561 } 524 525 spinlock_unlock(&box->lock); 526 interrupts_restore(ipl); 527 562 563 irq_spinlock_unlock(&box->lock, true); 564 528 565 /* Free unused call */ 529 566 if (call) … … 531 568 } 532 569 533 /** Clean sup all IPC communication of the current task.570 /** Clean up all IPC communication of the current task. 534 571 * 535 572 * Note: ipc_hangup sets returning answerbox to TASK->answerbox, you 536 573 * have to change it as well if you want to cleanup other tasks than TASK. 574 * 537 575 */ 538 576 void ipc_cleanup(void) 539 577 { 540 int i;541 call_t *call;542 ipl_t ipl;543 544 578 /* Disconnect all our phones ('ipc_phone_hangup') */ 579 size_t i; 545 580 for (i = 0; i < IPC_MAX_PHONES; i++) 546 581 ipc_phone_hangup(&TASK->phones[i]); 547 582 548 583 /* Unsubscribe from any event notifications. */ 549 584 event_cleanup_answerbox(&TASK->answerbox); 550 585 551 586 /* Disconnect all connected irqs */ 552 587 ipc_irq_cleanup(&TASK->answerbox); 553 588 554 589 /* Disconnect all phones connected to our regular answerbox */ 555 590 ipc_answerbox_slam_phones(&TASK->answerbox, false); 556 591 557 592 #ifdef CONFIG_UDEBUG 558 593 /* Clean up kbox thread and communications */ 559 594 ipc_kbox_cleanup(); 560 595 #endif 561 596 562 597 /* Answer all messages in 'calls' and 'dispatched_calls' queues */ 563 spinlock_lock(&TASK->answerbox.lock);598 irq_spinlock_lock(&TASK->answerbox.lock, true); 564 599 ipc_cleanup_call_list(&TASK->answerbox.dispatched_calls); 565 600 ipc_cleanup_call_list(&TASK->answerbox.calls); 566 spinlock_unlock(&TASK->answerbox.lock);601 irq_spinlock_unlock(&TASK->answerbox.lock, true); 567 602 568 603 /* Wait for all answers to interrupted synchronous calls to arrive */ 569 ipl = interrupts_disable();604 ipl_t ipl = interrupts_disable(); 570 605 while (!list_empty(&TASK->sync_box_head)) { 571 606 answerbox_t *box = list_get_instance(TASK->sync_box_head.next, 572 607 answerbox_t, sync_box_link); 573 608 574 609 list_remove(&box->sync_box_link); 575 call = ipc_wait_for_call(box, SYNCH_NO_TIMEOUT,610 call_t *call = ipc_wait_for_call(box, SYNCH_NO_TIMEOUT, 576 611 SYNCH_FLAGS_NONE); 577 612 ipc_call_free(call); … … 579 614 } 580 615 interrupts_restore(ipl); 581 616 582 617 /* Wait for all answers to asynchronous calls to arrive */ 583 while (1) { 584 /* Go through all phones, until all are FREE... */ 585 /* Locking not needed, no one else should modify 586 * it, when we are in cleanup */ 618 while (true) { 619 /* 620 * Go through all phones, until they are all FREE 621 * Locking is not needed, no one else should modify 622 * it when we are in cleanup 623 */ 587 624 for (i = 0; i < IPC_MAX_PHONES; i++) { 588 625 if (TASK->phones[i].state == IPC_PHONE_HUNGUP && … … 592 629 } 593 630 594 /* Just for sure, we might have had some 595 * IPC_PHONE_CONNECTING phones */ 631 /* 632 * Just for sure, we might have had some 633 * IPC_PHONE_CONNECTING phones 634 */ 596 635 if (TASK->phones[i].state == IPC_PHONE_CONNECTED) 597 636 ipc_phone_hangup(&TASK->phones[i]); 598 /* If the hangup succeeded, it has sent a HANGUP 637 638 /* 639 * If the hangup succeeded, it has sent a HANGUP 599 640 * message, the IPC is now in HUNGUP state, we 600 * wait for the reply to come */ 641 * wait for the reply to come 642 */ 601 643 602 644 if (TASK->phones[i].state != IPC_PHONE_FREE) 603 645 break; 604 646 } 605 /* Voila, got into cleanup */ 647 648 /* Got into cleanup */ 606 649 if (i == IPC_MAX_PHONES) 607 650 break; 608 651 609 call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT,652 call_t *call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT, 610 653 SYNCH_FLAGS_NONE); 611 654 ASSERT((call->flags & IPC_CALL_ANSWERED) || … … 619 662 if (!(call->flags & IPC_CALL_DISCARD_ANSWER)) 620 663 atomic_dec(&TASK->active_calls); 664 621 665 ipc_call_free(call); 622 666 } 623 667 } 624 668 625 626 /** Initilize IPC subsystem */ 669 /** Initilize IPC subsystem 670 * 671 */ 627 672 void ipc_init(void) 628 673 { … … 633 678 } 634 679 635 636 680 /** List answerbox contents. 637 681 * 638 * @param taskid Task ID. 682 * @param taskid Task ID. 683 * 639 684 */ 640 685 void ipc_print_task(task_id_t taskid) 641 686 { 642 task_t *task; 643 int i; 644 call_t *call; 645 link_t *tmp; 646 647 spinlock_lock(&tasks_lock); 648 task = task_find_by_id(taskid); 649 if (task) 650 spinlock_lock(&task->lock); 651 spinlock_unlock(&tasks_lock); 652 if (!task) 687 irq_spinlock_lock(&tasks_lock, true); 688 task_t *task = task_find_by_id(taskid); 689 690 if (!task) { 691 irq_spinlock_unlock(&tasks_lock, true); 653 692 return; 654 693 } 694 695 /* Hand-over-hand locking */ 696 irq_spinlock_exchange(&tasks_lock, &task->lock); 697 655 698 /* Print opened phones & details */ 656 699 printf("PHONE:\n"); 700 701 size_t i; 657 702 for (i = 0; i < IPC_MAX_PHONES; i++) { 658 703 if (SYNCH_FAILED(mutex_trylock(&task->phones[i].lock))) { 659 printf("% d: mutex busy\n", i);704 printf("%zu: mutex busy\n", i); 660 705 continue; 661 706 } 707 662 708 if (task->phones[i].state != IPC_PHONE_FREE) { 663 printf("%d: ", i); 709 printf("%zu: ", i); 710 664 711 switch (task->phones[i].state) { 665 712 case IPC_PHONE_CONNECTING: … … 667 714 break; 668 715 case IPC_PHONE_CONNECTED: 669 printf("connected to: %p ", 670 task->phones[i].callee);716 printf("connected to: %p ", 717 task->phones[i].callee); 671 718 break; 672 719 case IPC_PHONE_SLAMMED: 673 720 printf("slammed by: %p ", 674 task->phones[i].callee);721 task->phones[i].callee); 675 722 break; 676 723 case IPC_PHONE_HUNGUP: 677 724 printf("hung up - was: %p ", 678 task->phones[i].callee);725 task->phones[i].callee); 679 726 break; 680 727 default: 681 728 break; 682 729 } 683 printf("active: %ld\n", 730 731 printf("active: %" PRIun "\n", 684 732 atomic_get(&task->phones[i].active_calls)); 685 733 } 734 686 735 mutex_unlock(&task->phones[i].lock); 687 736 } 688 689 737 738 irq_spinlock_lock(&task->answerbox.lock, false); 739 740 link_t *cur; 741 690 742 /* Print answerbox - calls */ 691 spinlock_lock(&task->answerbox.lock);692 743 printf("ABOX - CALLS:\n"); 693 for ( tmp = task->answerbox.calls.next; tmp!= &task->answerbox.calls;694 tmp = tmp->next) {695 call = list_get_instance(tmp, call_t, link);744 for (cur = task->answerbox.calls.next; cur != &task->answerbox.calls; 745 cur = cur->next) { 746 call_t *call = list_get_instance(cur, call_t, link); 696 747 printf("Callid: %p Srctask:%" PRIu64 " M:%" PRIun 697 748 " A1:%" PRIun " A2:%" PRIun " A3:%" PRIun … … 703 754 call->flags); 704 755 } 705 /* Print answerbox - calls */ 756 757 /* Print answerbox - dispatched calls */ 706 758 printf("ABOX - DISPATCHED CALLS:\n"); 707 for ( tmp= task->answerbox.dispatched_calls.next;708 tmp != &task->answerbox.dispatched_calls;709 tmp = tmp->next) {710 call = list_get_instance(tmp, call_t, link);759 for (cur = task->answerbox.dispatched_calls.next; 760 cur != &task->answerbox.dispatched_calls; 761 cur = cur->next) { 762 call_t *call = list_get_instance(cur, call_t, link); 711 763 printf("Callid: %p Srctask:%" PRIu64 " M:%" PRIun 712 764 " A1:%" PRIun " A2:%" PRIun " A3:%" PRIun … … 718 770 call->flags); 719 771 } 720 /* Print answerbox - calls */ 772 773 /* Print answerbox - answers */ 721 774 printf("ABOX - ANSWERS:\n"); 722 for ( tmp= task->answerbox.answers.next;723 tmp!= &task->answerbox.answers;724 tmp = tmp->next) {725 call = list_get_instance(tmp, call_t, link);775 for (cur = task->answerbox.answers.next; 776 cur != &task->answerbox.answers; 777 cur = cur->next) { 778 call_t *call = list_get_instance(cur, call_t, link); 726 779 printf("Callid:%p M:%" PRIun " A1:%" PRIun " A2:%" PRIun 727 780 " A3:%" PRIun " A4:%" PRIun " A5:%" PRIun " Flags:%x\n", … … 731 784 call->flags); 732 785 } 733 734 spinlock_unlock(&task->answerbox.lock);735 spinlock_unlock(&task->lock);786 787 irq_spinlock_unlock(&task->answerbox.lock, false); 788 irq_spinlock_unlock(&task->lock, true); 736 789 } 737 790 -
kernel/generic/src/ipc/ipcrsc.c
rfb150d78 r46c20c8 45 45 * - hangup phone (the caller has hung up) 46 46 * - hangup phone (the answerbox is exiting) 47 * 47 * 48 48 * Locking strategy 49 49 * … … 85 85 * 86 86 * Phone hangup 87 * 87 * 88 88 * *** The caller hangs up (sys_ipc_hangup) *** 89 89 * - The phone is disconnected (no more messages can be sent over this phone), … … 99 99 * 100 100 * Call forwarding 101 * 101 * 102 102 * The call can be forwarded, so that the answer to call is passed directly 103 103 * to the original sender. However, this poses special problems regarding … … 114 114 * 115 115 * Cleanup strategy 116 * 116 * 117 117 * 1) Disconnect all our phones ('ipc_phone_hangup'). 118 118 * … … 123 123 * 124 124 * 4) Wait for all async answers to arrive and dispose of them. 125 * 125 * 126 126 */ 127 127 … … 137 137 * @todo Some speedup (hash table?) 138 138 * 139 * @param callid Userspace hash of the call. Currently it is the call 140 * structure kernel address. 141 * 142 * @return NULL on not found, otherwise pointer to the call 143 * structure. 139 * @param callid Userspace hash of the call. Currently it is the call 140 * structure kernel address. 141 * 142 * @return NULL on not found, otherwise pointer to the call 143 * structure. 144 * 144 145 */ 145 146 call_t *get_call(unative_t callid) 146 147 { 147 148 link_t *lst; 148 call_t * call, *result = NULL;149 150 spinlock_lock(&TASK->answerbox.lock);149 call_t *result = NULL; 150 151 irq_spinlock_lock(&TASK->answerbox.lock, true); 151 152 for (lst = TASK->answerbox.dispatched_calls.next; 152 153 lst != &TASK->answerbox.dispatched_calls; lst = lst->next) { 153 call = list_get_instance(lst, call_t, link);154 call_t *call = list_get_instance(lst, call_t, link); 154 155 if ((unative_t) call == callid) { 155 156 result = call; … … 157 158 } 158 159 } 159 spinlock_unlock(&TASK->answerbox.lock); 160 161 irq_spinlock_unlock(&TASK->answerbox.lock, true); 160 162 return result; 161 163 } … … 163 165 /** Allocate new phone slot in the specified task. 164 166 * 165 * @param t Task for which to allocate a new phone. 166 * 167 * @return New phone handle or -1 if the phone handle limit is 168 * exceeded. 169 */ 170 int phone_alloc(task_t *t) 171 { 172 int i; 173 174 spinlock_lock(&t->lock); 167 * @param task Task for which to allocate a new phone. 168 * 169 * @return New phone handle or -1 if the phone handle limit is 170 * exceeded. 171 * 172 */ 173 int phone_alloc(task_t *task) 174 { 175 irq_spinlock_lock(&task->lock, true); 176 177 size_t i; 175 178 for (i = 0; i < IPC_MAX_PHONES; i++) { 176 if ( t->phones[i].state == IPC_PHONE_HUNGUP&&177 atomic_get(&t->phones[i].active_calls) == 0)178 t ->phones[i].state = IPC_PHONE_FREE;179 180 if (t ->phones[i].state == IPC_PHONE_FREE) {181 t ->phones[i].state = IPC_PHONE_CONNECTING;179 if ((task->phones[i].state == IPC_PHONE_HUNGUP) && 180 (atomic_get(&task->phones[i].active_calls) == 0)) 181 task->phones[i].state = IPC_PHONE_FREE; 182 183 if (task->phones[i].state == IPC_PHONE_FREE) { 184 task->phones[i].state = IPC_PHONE_CONNECTING; 182 185 break; 183 186 } 184 187 } 185 spinlock_unlock(&t->lock); 186 188 189 irq_spinlock_unlock(&task->lock, true); 190 187 191 if (i == IPC_MAX_PHONES) 188 192 return -1; 189 193 190 194 return i; 191 195 } … … 193 197 /** Mark a phone structure free. 194 198 * 195 * @param phone Phone structure to be marked free. 199 * @param phone Phone structure to be marked free. 200 * 196 201 */ 197 202 static void phone_deallocp(phone_t *phone) … … 199 204 ASSERT(phone->state == IPC_PHONE_CONNECTING); 200 205 201 /* atomic operation */206 /* Atomic operation */ 202 207 phone->state = IPC_PHONE_FREE; 203 208 } … … 207 212 * All already sent messages will be correctly processed. 208 213 * 209 * @param phoneid Phone handle of the phone to be freed. 214 * @param phoneid Phone handle of the phone to be freed. 215 * 210 216 */ 211 217 void phone_dealloc(int phoneid) … … 216 222 /** Connect phone to a given answerbox. 217 223 * 218 * @param phoneid Phone handle to be connected.219 * @param box Answerbox to which to connect the phone handle.224 * @param phoneid Phone handle to be connected. 225 * @param box Answerbox to which to connect the phone handle. 220 226 * 221 227 * The procedure _enforces_ that the user first marks the phone 222 228 * busy (e.g. via phone_alloc) and then connects the phone, otherwise 223 229 * race condition may appear. 230 * 224 231 */ 225 232 void phone_connect(int phoneid, answerbox_t *box) -
kernel/generic/src/ipc/irq.c
rfb150d78 r46c20c8 31 31 * @{ 32 32 */ 33 33 34 /** 34 35 * @file … … 67 68 * structure are finished. Because we hold the hash table lock, we prevent new 68 69 * IRQs from taking new references to the IRQ structure. 70 * 69 71 */ 70 72 … … 81 83 /** Free the top-half pseudocode. 82 84 * 83 * @param code Pointer to the top-half pseudocode. 85 * @param code Pointer to the top-half pseudocode. 86 * 84 87 */ 85 88 static void code_free(irq_code_t *code) … … 93 96 /** Copy the top-half pseudocode from userspace into the kernel. 94 97 * 95 * @param ucode Userspace address of the top-half pseudocode. 96 * 97 * @return Kernel address of the copied pseudocode. 98 * @param ucode Userspace address of the top-half pseudocode. 99 * 100 * @return Kernel address of the copied pseudocode. 101 * 98 102 */ 99 103 static irq_code_t *code_from_uspace(irq_code_t *ucode) 100 104 { 101 irq_code_t *code; 102 irq_cmd_t *ucmds; 103 int rc; 104 105 code = malloc(sizeof(*code), 0); 106 rc = copy_from_uspace(code, ucode, sizeof(*code)); 105 irq_code_t *code = malloc(sizeof(*code), 0); 106 int rc = copy_from_uspace(code, ucode, sizeof(*code)); 107 107 if (rc != 0) { 108 108 free(code); … … 114 114 return NULL; 115 115 } 116 ucmds = code->cmds; 116 117 irq_cmd_t *ucmds = code->cmds; 117 118 code->cmds = malloc(sizeof(code->cmds[0]) * code->cmdcount, 0); 118 119 rc = copy_from_uspace(code->cmds, ucmds, … … 123 124 return NULL; 124 125 } 125 126 126 127 return code; 127 128 } … … 141 142 unative_t method, irq_code_t *ucode) 142 143 { 143 ipl_t ipl;144 irq_code_t *code;145 irq_t *irq;146 link_t *hlp;147 144 unative_t key[] = { 148 145 (unative_t) inr, … … 150 147 }; 151 148 149 irq_code_t *code; 152 150 if (ucode) { 153 151 code = code_from_uspace(ucode); 154 152 if (!code) 155 153 return EBADMEM; 156 } else {154 } else 157 155 code = NULL; 158 }159 156 160 157 /* 161 158 * Allocate and populate the IRQ structure. 162 159 */ 163 irq = malloc(sizeof(irq_t), 0); 160 irq_t *irq = malloc(sizeof(irq_t), 0); 161 164 162 irq_initialize(irq); 165 163 irq->devno = devno; … … 177 175 * answerbox's list. 178 176 */ 179 i pl = interrupts_disable();180 spinlock_lock(&irq_uspace_hash_table_lock);181 hlp = hash_table_find(&irq_uspace_hash_table, key);177 irq_spinlock_lock(&irq_uspace_hash_table_lock, true); 178 179 link_t *hlp = hash_table_find(&irq_uspace_hash_table, key); 182 180 if (hlp) { 183 irq_t *hirq __attribute__((unused)) 184 = hash_table_get_instance(hlp, irq_t, link); 181 irq_t *hirq = hash_table_get_instance(hlp, irq_t, link); 185 182 186 183 /* hirq is locked */ 187 spinlock_unlock(&hirq->lock);184 irq_spinlock_unlock(&hirq->lock, false); 188 185 code_free(code); 189 spinlock_unlock(&irq_uspace_hash_table_lock); 186 irq_spinlock_unlock(&irq_uspace_hash_table_lock, true); 187 190 188 free(irq); 191 interrupts_restore(ipl);192 189 return EEXISTS; 193 190 } 194 191 195 spinlock_lock(&irq->lock); /* Not really necessary, but paranoid */ 196 spinlock_lock(&box->irq_lock); 192 /* Locking is not really necessary, but paranoid */ 193 irq_spinlock_lock(&irq->lock, false); 194 irq_spinlock_lock(&box->irq_lock, false); 195 197 196 hash_table_insert(&irq_uspace_hash_table, key, &irq->link); 198 197 list_append(&irq->notif_cfg.link, &box->irq_head); 199 spinlock_unlock(&box->irq_lock);200 spinlock_unlock(&irq->lock);201 spinlock_unlock(&irq_uspace_hash_table_lock);202 203 interrupts_restore(ipl);198 199 irq_spinlock_unlock(&box->irq_lock, false); 200 irq_spinlock_unlock(&irq->lock, false); 201 irq_spinlock_unlock(&irq_uspace_hash_table_lock, true); 202 204 203 return EOK; 205 204 } … … 207 206 /** Unregister task from IRQ notification. 208 207 * 209 * @param box Answerbox associated with the notification. 210 * @param inr IRQ number. 211 * @param devno Device number. 208 * @param box Answerbox associated with the notification. 209 * @param inr IRQ number. 210 * @param devno Device number. 211 * 212 212 */ 213 213 int ipc_irq_unregister(answerbox_t *box, inr_t inr, devno_t devno) 214 214 { 215 ipl_t ipl;216 215 unative_t key[] = { 217 216 (unative_t) inr, 218 217 (unative_t) devno 219 218 }; 220 link_t *lnk; 221 irq_t *irq; 222 223 ipl = interrupts_disable(); 224 spinlock_lock(&irq_uspace_hash_table_lock); 225 lnk = hash_table_find(&irq_uspace_hash_table, key); 219 220 irq_spinlock_lock(&irq_uspace_hash_table_lock, true); 221 link_t *lnk = hash_table_find(&irq_uspace_hash_table, key); 226 222 if (!lnk) { 227 spinlock_unlock(&irq_uspace_hash_table_lock); 228 interrupts_restore(ipl); 223 irq_spinlock_unlock(&irq_uspace_hash_table_lock, true); 229 224 return ENOENT; 230 225 } 231 irq = hash_table_get_instance(lnk, irq_t, link); 226 227 irq_t *irq = hash_table_get_instance(lnk, irq_t, link); 228 232 229 /* irq is locked */ 233 spinlock_lock(&box->irq_lock);230 irq_spinlock_lock(&box->irq_lock, false); 234 231 235 232 ASSERT(irq->notif_cfg.answerbox == box); … … 237 234 /* Free up the pseudo code and associated structures. */ 238 235 code_free(irq->notif_cfg.code); 239 240 /* Remove the IRQ from the answerbox's list. */ 236 237 /* Remove the IRQ from the answerbox's list. */ 241 238 list_remove(&irq->notif_cfg.link); 242 239 243 240 /* 244 241 * We need to drop the IRQ lock now because hash_table_remove() will try … … 248 245 * the meantime. 249 246 */ 250 spinlock_unlock(&irq->lock);251 247 irq_spinlock_unlock(&irq->lock, false); 248 252 249 /* Remove the IRQ from the uspace IRQ hash table. */ 253 250 hash_table_remove(&irq_uspace_hash_table, key, 2); 254 251 255 spinlock_unlock(&irq_uspace_hash_table_lock);256 spinlock_unlock(&box->irq_lock);252 irq_spinlock_unlock(&box->irq_lock, false); 253 irq_spinlock_unlock(&irq_uspace_hash_table_lock, true); 257 254 258 255 /* Free up the IRQ structure. */ 259 256 free(irq); 260 257 261 interrupts_restore(ipl);262 258 return EOK; 263 259 } 264 265 260 266 261 /** Disconnect all IRQ notifications from an answerbox. … … 270 265 * send notifications to it. 271 266 * 272 * @param box Answerbox for which we want to carry out the cleanup. 267 * @param box Answerbox for which we want to carry out the cleanup. 268 * 273 269 */ 274 270 void ipc_irq_cleanup(answerbox_t *box) 275 271 { 276 ipl_t ipl;277 278 272 loop: 279 ipl = interrupts_disable(); 280 spinlock_lock(&irq_uspace_hash_table_lock); 281 spinlock_lock(&box->irq_lock); 273 irq_spinlock_lock(&irq_uspace_hash_table_lock, true); 274 irq_spinlock_lock(&box->irq_lock, false); 282 275 283 276 while (box->irq_head.next != &box->irq_head) { 284 link_t *cur = box->irq_head.next;285 irq_t *irq;286 277 DEADLOCK_PROBE_INIT(p_irqlock); 287 unative_t key[2]; 288 289 irq = list_get_instance(cur, irq_t, notif_cfg.link); 290 if (!spinlock_trylock(&irq->lock)) { 278 279 irq_t *irq = list_get_instance(box->irq_head.next, irq_t, 280 notif_cfg.link); 281 282 if (!irq_spinlock_trylock(&irq->lock)) { 291 283 /* 292 284 * Avoid deadlock by trying again. 293 285 */ 294 spinlock_unlock(&box->irq_lock); 295 spinlock_unlock(&irq_uspace_hash_table_lock); 296 interrupts_restore(ipl); 286 irq_spinlock_unlock(&box->irq_lock, false); 287 irq_spinlock_unlock(&irq_uspace_hash_table_lock, true); 297 288 DEADLOCK_PROBE(p_irqlock, DEADLOCK_THRESHOLD); 298 289 goto loop; 299 290 } 291 292 unative_t key[2]; 300 293 key[0] = irq->inr; 301 294 key[1] = irq->devno; 302 303 295 304 296 ASSERT(irq->notif_cfg.answerbox == box); … … 317 309 * didn't drop the hash table lock in the meantime. 318 310 */ 319 spinlock_unlock(&irq->lock);311 irq_spinlock_unlock(&irq->lock, false); 320 312 321 313 /* Remove from the hash table. */ … … 325 317 } 326 318 327 spinlock_unlock(&box->irq_lock); 328 spinlock_unlock(&irq_uspace_hash_table_lock); 329 interrupts_restore(ipl); 319 irq_spinlock_unlock(&box->irq_lock, false); 320 irq_spinlock_unlock(&irq_uspace_hash_table_lock, true); 330 321 } 331 322 332 323 /** Add a call to the proper answerbox queue. 333 324 * 334 * Assume irq->lock is locked. 335 * 336 * @param irq IRQ structure referencing the target answerbox. 337 * @param call IRQ notification call. 325 * Assume irq->lock is locked and interrupts disabled. 326 * 327 * @param irq IRQ structure referencing the target answerbox. 328 * @param call IRQ notification call. 329 * 338 330 */ 339 331 static void send_call(irq_t *irq, call_t *call) 340 332 { 341 spinlock_lock(&irq->notif_cfg.answerbox->irq_lock);333 irq_spinlock_lock(&irq->notif_cfg.answerbox->irq_lock, false); 342 334 list_append(&call->link, &irq->notif_cfg.answerbox->irq_notifs); 343 spinlock_unlock(&irq->notif_cfg.answerbox->irq_lock);344 335 irq_spinlock_unlock(&irq->notif_cfg.answerbox->irq_lock, false); 336 345 337 waitq_wakeup(&irq->notif_cfg.answerbox->wq, WAKEUP_FIRST); 346 338 } … … 348 340 /** Apply the top-half pseudo code to find out whether to accept the IRQ or not. 349 341 * 350 * @param irq IRQ structure. 351 * 352 * @return IRQ_ACCEPT if the interrupt is accepted by the 353 * pseudocode. IRQ_DECLINE otherwise. 342 * @param irq IRQ structure. 343 * 344 * @return IRQ_ACCEPT if the interrupt is accepted by the 345 * pseudocode, IRQ_DECLINE otherwise. 346 * 354 347 */ 355 348 irq_ownership_t ipc_irq_top_half_claim(irq_t *irq) 356 349 { 357 unsigned int i;358 unative_t dstval;359 350 irq_code_t *code = irq->notif_cfg.code; 360 unative_t *scratch = irq->notif_cfg.scratch; 361 351 uint32_t *scratch = irq->notif_cfg.scratch; 362 352 363 353 if (!irq->notif_cfg.notify) … … 367 357 return IRQ_DECLINE; 368 358 359 size_t i; 369 360 for (i = 0; i < code->cmdcount; i++) { 370 unsigned int srcarg = code->cmds[i].srcarg; 371 unsigned int dstarg = code->cmds[i].dstarg; 361 uint32_t dstval; 362 uintptr_t srcarg = code->cmds[i].srcarg; 363 uintptr_t dstarg = code->cmds[i].dstarg; 372 364 373 365 if (srcarg >= IPC_CALL_LEN) 374 366 break; 367 375 368 if (dstarg >= IPC_CALL_LEN) 376 369 break; … … 405 398 break; 406 399 case CMD_BTEST: 407 if ( srcarg && dstarg) {400 if ((srcarg) && (dstarg)) { 408 401 dstval = scratch[srcarg] & code->cmds[i].value; 409 402 scratch[dstarg] = dstval; … … 411 404 break; 412 405 case CMD_PREDICATE: 413 if ( srcarg && !scratch[srcarg]) {406 if ((srcarg) && (!scratch[srcarg])) { 414 407 i += code->cmds[i].value; 415 408 continue; … … 427 420 } 428 421 429 430 422 /* IRQ top-half handler. 431 423 * 432 424 * We expect interrupts to be disabled and the irq->lock already held. 433 425 * 434 * @param irq IRQ structure. 426 * @param irq IRQ structure. 427 * 435 428 */ 436 429 void ipc_irq_top_half_handler(irq_t *irq) … … 438 431 ASSERT(irq); 439 432 433 ASSERT(interrupts_disabled()); 434 ASSERT(irq_spinlock_locked(&irq->lock)); 435 440 436 if (irq->notif_cfg.answerbox) { 441 call_t *call; 442 443 call = ipc_call_alloc(FRAME_ATOMIC); 437 call_t *call = ipc_call_alloc(FRAME_ATOMIC); 444 438 if (!call) 445 439 return; … … 448 442 /* Put a counter to the message */ 449 443 call->priv = ++irq->notif_cfg.counter; 450 444 451 445 /* Set up args */ 452 446 IPC_SET_METHOD(call->data, irq->notif_cfg.method); … … 456 450 IPC_SET_ARG4(call->data, irq->notif_cfg.scratch[4]); 457 451 IPC_SET_ARG5(call->data, irq->notif_cfg.scratch[5]); 458 452 459 453 send_call(irq, call); 460 454 } … … 463 457 /** Send notification message. 464 458 * 465 * @param irq IRQ structure. 466 * @param a1 Driver-specific payload argument. 467 * @param a2 Driver-specific payload argument. 468 * @param a3 Driver-specific payload argument. 469 * @param a4 Driver-specific payload argument. 470 * @param a5 Driver-specific payload argument. 459 * @param irq IRQ structure. 460 * @param a1 Driver-specific payload argument. 461 * @param a2 Driver-specific payload argument. 462 * @param a3 Driver-specific payload argument. 463 * @param a4 Driver-specific payload argument. 464 * @param a5 Driver-specific payload argument. 465 * 471 466 */ 472 467 void ipc_irq_send_msg(irq_t *irq, unative_t a1, unative_t a2, unative_t a3, 473 468 unative_t a4, unative_t a5) 474 469 { 475 call_t *call; 476 477 spinlock_lock(&irq->lock); 478 470 irq_spinlock_lock(&irq->lock, true); 471 479 472 if (irq->notif_cfg.answerbox) { 480 call = ipc_call_alloc(FRAME_ATOMIC);473 call_t *call = ipc_call_alloc(FRAME_ATOMIC); 481 474 if (!call) { 482 spinlock_unlock(&irq->lock);475 irq_spinlock_unlock(&irq->lock, true); 483 476 return; 484 477 } 478 485 479 call->flags |= IPC_CALL_NOTIF; 486 480 /* Put a counter to the message */ 487 481 call->priv = ++irq->notif_cfg.counter; 488 482 489 483 IPC_SET_METHOD(call->data, irq->notif_cfg.method); 490 484 IPC_SET_ARG1(call->data, a1); … … 496 490 send_call(irq, call); 497 491 } 498 spinlock_unlock(&irq->lock); 492 493 irq_spinlock_unlock(&irq->lock, true); 499 494 } 500 495 -
kernel/generic/src/ipc/kbox.c
rfb150d78 r46c20c8 47 47 void ipc_kbox_cleanup(void) 48 48 { 49 ipl_t ipl; 50 bool have_kb_thread; 51 52 /* 49 /* 53 50 * Only hold kb.cleanup_lock while setting kb.finished - 54 51 * this is enough. … … 57 54 TASK->kb.finished = true; 58 55 mutex_unlock(&TASK->kb.cleanup_lock); 59 60 have_kb_thread = (TASK->kb.thread != NULL);61 56 57 bool have_kb_thread = (TASK->kb.thread != NULL); 58 62 59 /* 63 60 * From now on nobody will try to connect phones or attach 64 61 * kbox threads 65 62 */ 66 63 67 64 /* 68 65 * Disconnect all phones connected to our kbox. Passing true for … … 72 69 */ 73 70 ipc_answerbox_slam_phones(&TASK->kb.box, have_kb_thread); 74 75 /* 71 72 /* 76 73 * If the task was being debugged, clean up debugging session. 77 74 * This is necessarry as slamming the phones won't force 78 75 * kbox thread to clean it up since sender != debugger. 79 76 */ 80 ipl = interrupts_disable(); 81 spinlock_lock(&TASK->lock); 77 mutex_lock(&TASK->udebug.lock); 82 78 udebug_task_cleanup(TASK); 83 spinlock_unlock(&TASK->lock); 84 interrupts_restore(ipl); 79 mutex_unlock(&TASK->udebug.lock); 85 80 86 81 if (have_kb_thread) { … … 91 86 TASK->kb.thread = NULL; 92 87 } 93 88 94 89 /* Answer all messages in 'calls' and 'dispatched_calls' queues. */ 95 spinlock_lock(&TASK->kb.box.lock);90 irq_spinlock_lock(&TASK->kb.box.lock, true); 96 91 ipc_cleanup_call_list(&TASK->kb.box.dispatched_calls); 97 92 ipc_cleanup_call_list(&TASK->kb.box.calls); 98 spinlock_unlock(&TASK->kb.box.lock);93 irq_spinlock_unlock(&TASK->kb.box.lock, true); 99 94 } 100 95 101 96 /** Handle hangup message in kbox. 102 97 * 103 * @param call The IPC_M_PHONE_HUNGUP call structure. 104 * @param last Output, the function stores @c true here if 105 * this was the last phone, @c false otherwise. 106 **/ 98 * @param call The IPC_M_PHONE_HUNGUP call structure. 99 * @param last Output, the function stores @c true here if 100 * this was the last phone, @c false otherwise. 101 * 102 */ 107 103 static void kbox_proc_phone_hungup(call_t *call, bool *last) 108 104 { 109 ipl_t ipl;110 111 105 /* Was it our debugger, who hung up? */ 112 106 if (call->sender == TASK->udebug.debugger) { 113 107 /* Terminate debugging session (if any). */ 114 108 LOG("Terminate debugging session."); 115 ipl = interrupts_disable(); 116 spinlock_lock(&TASK->lock); 109 mutex_lock(&TASK->udebug.lock); 117 110 udebug_task_cleanup(TASK); 118 spinlock_unlock(&TASK->lock); 119 interrupts_restore(ipl); 111 mutex_unlock(&TASK->udebug.lock); 120 112 } else { 121 113 LOG("Was not debugger."); 122 114 } 123 115 124 116 LOG("Continue with hangup message."); 125 117 IPC_SET_RETVAL(call->data, 0); 126 118 ipc_answer(&TASK->kb.box, call); 127 128 ipl = interrupts_disable(); 129 spinlock_lock(&TASK->lock); 130 spinlock_lock(&TASK->kb.box.lock); 119 120 mutex_lock(&TASK->kb.cleanup_lock); 121 122 irq_spinlock_lock(&TASK->lock, true); 123 irq_spinlock_lock(&TASK->kb.box.lock, false); 131 124 if (list_empty(&TASK->kb.box.connected_phones)) { 132 125 /* … … 134 127 * gets freed and signal to the caller. 135 128 */ 136 129 137 130 /* Only detach kbox thread unless already terminating. */ 138 mutex_lock(&TASK->kb.cleanup_lock);139 131 if (TASK->kb.finished == false) { 140 132 /* Detach kbox thread so it gets freed from memory. */ … … 142 134 TASK->kb.thread = NULL; 143 135 } 144 mutex_unlock(&TASK->kb.cleanup_lock); 145 136 146 137 LOG("Phone list is empty."); 147 138 *last = true; 148 } else {139 } else 149 140 *last = false; 150 }151 152 spinlock_unlock(&TASK->kb.box.lock);153 spinlock_unlock(&TASK->lock);154 interrupts_restore(ipl);141 142 irq_spinlock_unlock(&TASK->kb.box.lock, false); 143 irq_spinlock_unlock(&TASK->lock, true); 144 145 mutex_unlock(&TASK->kb.cleanup_lock); 155 146 } 156 147 … … 160 151 * when all phones are disconnected from the kbox. 161 152 * 162 * @param arg Ignored. 153 * @param arg Ignored. 154 * 163 155 */ 164 156 static void kbox_thread_proc(void *arg) 165 157 { 166 call_t *call; 167 bool done; 168 169 (void)arg; 158 (void) arg; 170 159 LOG("Starting."); 171 done = false;172 160 bool done = false; 161 173 162 while (!done) { 174 call = ipc_wait_for_call(&TASK->kb.box, SYNCH_NO_TIMEOUT,163 call_t *call = ipc_wait_for_call(&TASK->kb.box, SYNCH_NO_TIMEOUT, 175 164 SYNCH_FLAGS_NONE); 176 165 177 166 if (call == NULL) 178 continue; /* Try again. */179 167 continue; /* Try again. */ 168 180 169 switch (IPC_GET_METHOD(call->data)) { 181 170 182 171 case IPC_M_DEBUG_ALL: 183 172 /* Handle debug call. */ 184 173 udebug_call_receive(call); 185 174 break; 186 175 187 176 case IPC_M_PHONE_HUNGUP: 188 177 /* … … 193 182 kbox_proc_phone_hungup(call, &done); 194 183 break; 195 184 196 185 default: 197 186 /* Ignore */ … … 199 188 } 200 189 } 201 190 202 191 LOG("Exiting."); 203 192 } 204 193 205 194 206 /** 207 * Connect phone to a task kernel-box specified by id. 195 /** Connect phone to a task kernel-box specified by id. 208 196 * 209 197 * Note that this is not completely atomic. For optimisation reasons, the task … … 212 200 * cleanup code. 213 201 * 214 * @return Phone id on success, or negative error code. 202 * @return Phone id on success, or negative error code. 203 * 215 204 */ 216 205 int ipc_connect_kbox(task_id_t taskid) 217 206 { 218 int newphid; 219 task_t *ta; 220 thread_t *kb_thread; 221 ipl_t ipl; 222 223 ipl = interrupts_disable(); 224 spinlock_lock(&tasks_lock); 225 226 ta = task_find_by_id(taskid); 227 if (ta == NULL) { 228 spinlock_unlock(&tasks_lock); 229 interrupts_restore(ipl); 207 irq_spinlock_lock(&tasks_lock, true); 208 209 task_t *task = task_find_by_id(taskid); 210 if (task == NULL) { 211 irq_spinlock_unlock(&tasks_lock, true); 230 212 return ENOENT; 231 213 } 232 233 atomic_inc(&ta->refcount); 234 235 spinlock_unlock(&tasks_lock); 236 interrupts_restore(ipl); 237 238 mutex_lock(&ta->kb.cleanup_lock); 239 240 if (atomic_predec(&ta->refcount) == 0) { 241 mutex_unlock(&ta->kb.cleanup_lock); 242 task_destroy(ta); 214 215 atomic_inc(&task->refcount); 216 217 irq_spinlock_unlock(&tasks_lock, true); 218 219 mutex_lock(&task->kb.cleanup_lock); 220 221 if (atomic_predec(&task->refcount) == 0) { 222 mutex_unlock(&task->kb.cleanup_lock); 223 task_destroy(task); 243 224 return ENOENT; 244 225 } 245 246 if (ta ->kb.finished != false) {247 mutex_unlock(&ta ->kb.cleanup_lock);226 227 if (task->kb.finished != false) { 228 mutex_unlock(&task->kb.cleanup_lock); 248 229 return EINVAL; 249 230 } 250 251 newphid = phone_alloc(TASK);231 232 int newphid = phone_alloc(TASK); 252 233 if (newphid < 0) { 253 mutex_unlock(&ta ->kb.cleanup_lock);234 mutex_unlock(&task->kb.cleanup_lock); 254 235 return ELIMIT; 255 236 } 256 237 257 238 /* Connect the newly allocated phone to the kbox */ 258 ipc_phone_connect(&TASK->phones[newphid], &ta ->kb.box);259 260 if (ta ->kb.thread != NULL) {261 mutex_unlock(&ta ->kb.cleanup_lock);239 ipc_phone_connect(&TASK->phones[newphid], &task->kb.box); 240 241 if (task->kb.thread != NULL) { 242 mutex_unlock(&task->kb.cleanup_lock); 262 243 return newphid; 263 244 } 264 245 265 246 /* Create a kbox thread */ 266 kb_thread = thread_create(kbox_thread_proc, NULL, ta, 0,247 thread_t *kb_thread = thread_create(kbox_thread_proc, NULL, task, 0, 267 248 "kbox", false); 268 249 if (!kb_thread) { 269 mutex_unlock(&ta ->kb.cleanup_lock);250 mutex_unlock(&task->kb.cleanup_lock); 270 251 return ENOMEM; 271 252 } 272 273 ta ->kb.thread = kb_thread;253 254 task->kb.thread = kb_thread; 274 255 thread_ready(kb_thread); 275 276 mutex_unlock(&ta ->kb.cleanup_lock);277 256 257 mutex_unlock(&task->kb.cleanup_lock); 258 278 259 return newphid; 279 260 } -
kernel/generic/src/ipc/sysipc.c
rfb150d78 r46c20c8 56 56 * requests. 57 57 */ 58 #define DATA_XFER_LIMIT (64 * 1024) 59 60 #define GET_CHECK_PHONE(phone, phoneid, err) \ 61 { \ 62 if (phoneid > IPC_MAX_PHONES) { \ 63 err \ 64 } \ 65 phone = &TASK->phones[phoneid]; \ 66 } 67 68 #define STRUCT_TO_USPACE(dst, src) copy_to_uspace(dst, src, sizeof(*(src))) 58 #define DATA_XFER_LIMIT (64 * 1024) 59 60 #define STRUCT_TO_USPACE(dst, src) copy_to_uspace((dst), (src), sizeof(*(src))) 61 62 /** Get phone from the current task by ID. 63 * 64 * @param phoneid Phone ID. 65 * @param phone Place to store pointer to phone. 66 * 67 * @return EOK on success, EINVAL if ID is invalid. 68 * 69 */ 70 static int phone_get(unative_t phoneid, phone_t **phone) 71 { 72 if (phoneid >= IPC_MAX_PHONES) 73 return EINVAL; 74 75 *phone = &TASK->phones[phoneid]; 76 return EOK; 77 } 69 78 70 79 /** Decide if the method is a system method. 71 80 * 72 * @param method Method to be decided.73 * 74 * @return Return 1if the method is a system method.75 * Otherwise return 0.76 */ 77 static inline intmethod_is_system(unative_t method)81 * @param method Method to be decided. 82 * 83 * @return true if the method is a system method. 84 * 85 */ 86 static inline bool method_is_system(unative_t method) 78 87 { 79 88 if (method <= IPC_M_LAST_SYSTEM) 80 return 1; 81 return 0; 89 return true; 90 91 return false; 82 92 } 83 93 … … 87 97 * it is useless 88 98 * 89 * @param method Method to be decided.90 * 91 * @return Return 1if the method is forwardable.92 * Otherwise return 0.93 */ 94 static inline intmethod_is_forwardable(unative_t method)99 * @param method Method to be decided. 100 * 101 * @return true if the method is forwardable. 102 * 103 */ 104 static inline bool method_is_forwardable(unative_t method) 95 105 { 96 106 switch (method) { … … 99 109 case IPC_M_PHONE_HUNGUP: 100 110 /* This message is meant only for the original recipient. */ 101 return 0;111 return false; 102 112 default: 103 return 1;113 return true; 104 114 } 105 115 } … … 109 119 * - some system messages may be forwarded but their content cannot be altered 110 120 * 111 * @param method Method to be decided.112 * 113 * @return Return 1if the method is immutable on forward.114 * Otherwise return 0.115 */ 116 static inline intmethod_is_immutable(unative_t method)121 * @param method Method to be decided. 122 * 123 * @return true if the method is immutable on forward. 124 * 125 */ 126 static inline bool method_is_immutable(unative_t method) 117 127 { 118 128 switch (method) { … … 121 131 case IPC_M_DATA_WRITE: 122 132 case IPC_M_DATA_READ: 123 return 1;133 return true; 124 134 default: 125 return 0;135 return false; 126 136 } 127 137 } … … 135 145 * for answer_preprocess(). 136 146 * 137 * @param call Call structure to be decided.138 * 139 * @return Return 1if the old call contents should be saved.140 * Return 0 otherwise.141 */ 142 static inline intanswer_need_old(call_t *call)147 * @param call Call structure to be decided. 148 * 149 * @return true if the old call contents should be saved. 150 * 151 */ 152 static inline bool answer_need_old(call_t *call) 143 153 { 144 154 switch (IPC_GET_METHOD(call->data)) { … … 151 161 case IPC_M_DATA_WRITE: 152 162 case IPC_M_DATA_READ: 153 return 1;163 return true; 154 164 default: 155 return 0;165 return false; 156 166 } 157 167 } … … 161 171 * This function is called directly after sys_ipc_answer(). 162 172 * 163 * @param answer Call structure with the answer. 164 * @param olddata Saved data of the request. 165 * 166 * @return Return 0 on success or an error code. 173 * @param answer Call structure with the answer. 174 * @param olddata Saved data of the request. 175 * 176 * @return Return 0 on success or an error code. 177 * 167 178 */ 168 179 static inline int answer_preprocess(call_t *answer, ipc_data_t *olddata) 169 180 { 170 int phoneid;171 172 181 if ((native_t) IPC_GET_RETVAL(answer->data) == EHANGUP) { 173 182 /* In case of forward, hangup the forwared phone, … … 175 184 */ 176 185 mutex_lock(&answer->data.phone->lock); 177 spinlock_lock(&TASK->answerbox.lock);186 irq_spinlock_lock(&TASK->answerbox.lock, true); 178 187 if (answer->data.phone->state == IPC_PHONE_CONNECTED) { 179 188 list_remove(&answer->data.phone->link); 180 189 answer->data.phone->state = IPC_PHONE_SLAMMED; 181 190 } 182 spinlock_unlock(&TASK->answerbox.lock);191 irq_spinlock_unlock(&TASK->answerbox.lock, true); 183 192 mutex_unlock(&answer->data.phone->lock); 184 193 } 185 194 186 195 if (!olddata) 187 196 return 0; 188 197 189 198 if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECTION_CLONE) { 190 phoneid = IPC_GET_ARG1(*olddata); 191 phone_t *phone = &TASK->phones[phoneid]; 199 int phoneid = IPC_GET_ARG1(*olddata); 200 phone_t *phone = &TASK->phones[phoneid]; 201 192 202 if (IPC_GET_RETVAL(answer->data) != EOK) { 193 203 /* … … 201 211 mutex_lock(&phone->lock); 202 212 if (phone->state == IPC_PHONE_CONNECTED) { 203 spinlock_lock(&phone->callee->lock);213 irq_spinlock_lock(&phone->callee->lock, true); 204 214 list_remove(&phone->link); 205 215 phone->state = IPC_PHONE_SLAMMED; 206 spinlock_unlock(&phone->callee->lock);216 irq_spinlock_unlock(&phone->callee->lock, true); 207 217 } 208 218 mutex_unlock(&phone->lock); 209 219 } 210 220 } else if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_ME) { 211 phone_t *phone = (phone_t *)IPC_GET_ARG5(*olddata); 221 phone_t *phone = (phone_t *) IPC_GET_ARG5(*olddata); 222 212 223 if (IPC_GET_RETVAL(answer->data) != EOK) { 213 224 /* … … 219 230 mutex_lock(&phone->lock); 220 231 if (phone->state == IPC_PHONE_CONNECTED) { 221 spinlock_lock(&phone->callee->lock);232 irq_spinlock_lock(&phone->callee->lock, true); 222 233 list_remove(&phone->link); 223 234 phone->state = IPC_PHONE_SLAMMED; 224 spinlock_unlock(&phone->callee->lock);235 irq_spinlock_unlock(&phone->callee->lock, true); 225 236 } 226 237 mutex_unlock(&phone->lock); 227 238 } 228 239 } else if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_TO_ME) { 229 phoneid = IPC_GET_ARG5(*olddata); 240 int phoneid = IPC_GET_ARG5(*olddata); 241 230 242 if (IPC_GET_RETVAL(answer->data) != EOK) { 231 243 /* The connection was not accepted */ … … 247 259 if (!IPC_GET_RETVAL(answer->data)) { 248 260 /* Accepted, handle as_area receipt */ 249 ipl_t ipl;250 int rc;251 as_t *as;252 261 253 ipl = interrupts_disable(); 254 spinlock_lock(&answer->sender->lock); 255 as = answer->sender->as; 256 spinlock_unlock(&answer->sender->lock); 257 interrupts_restore(ipl); 262 irq_spinlock_lock(&answer->sender->lock, true); 263 as_t *as = answer->sender->as; 264 irq_spinlock_unlock(&answer->sender->lock, true); 258 265 259 rc = as_area_share(as, IPC_GET_ARG1(*olddata),266 int rc = as_area_share(as, IPC_GET_ARG1(*olddata), 260 267 IPC_GET_ARG2(*olddata), AS, 261 268 IPC_GET_ARG1(answer->data), IPC_GET_ARG3(*olddata)); … … 265 272 } else if (IPC_GET_METHOD(*olddata) == IPC_M_SHARE_IN) { 266 273 if (!IPC_GET_RETVAL(answer->data)) { 267 i pl_t ipl;268 as_t *as ;269 i nt rc;274 irq_spinlock_lock(&answer->sender->lock, true); 275 as_t *as = answer->sender->as; 276 irq_spinlock_unlock(&answer->sender->lock, true); 270 277 271 ipl = interrupts_disable(); 272 spinlock_lock(&answer->sender->lock); 273 as = answer->sender->as; 274 spinlock_unlock(&answer->sender->lock); 275 interrupts_restore(ipl); 276 277 rc = as_area_share(AS, IPC_GET_ARG1(answer->data), 278 int rc = as_area_share(AS, IPC_GET_ARG1(answer->data), 278 279 IPC_GET_ARG2(*olddata), as, IPC_GET_ARG1(*olddata), 279 280 IPC_GET_ARG2(answer->data)); … … 294 295 */ 295 296 IPC_SET_ARG1(answer->data, dst); 296 297 297 298 answer->buffer = malloc(size, 0); 298 299 int rc = copy_from_uspace(answer->buffer, … … 313 314 if (!IPC_GET_RETVAL(answer->data)) { 314 315 /* The recipient agreed to receive data. */ 315 int rc; 316 uintptr_t dst; 317 size_t size; 318 size_t max_size; 319 320 dst = (uintptr_t)IPC_GET_ARG1(answer->data); 321 size = (size_t)IPC_GET_ARG2(answer->data); 322 max_size = (size_t)IPC_GET_ARG2(*olddata); 323 316 uintptr_t dst = (uintptr_t)IPC_GET_ARG1(answer->data); 317 size_t size = (size_t)IPC_GET_ARG2(answer->data); 318 size_t max_size = (size_t)IPC_GET_ARG2(*olddata); 319 324 320 if (size <= max_size) { 325 rc = copy_to_uspace((void *) dst,321 int rc = copy_to_uspace((void *) dst, 326 322 answer->buffer, size); 327 323 if (rc) … … 334 330 answer->buffer = NULL; 335 331 } 332 336 333 return 0; 337 334 } … … 345 342 mutex_lock(&p2->lock); 346 343 mutex_lock(&p1->lock); 347 } else {344 } else 348 345 mutex_lock(&p1->lock); 349 }350 346 } 351 347 … … 359 355 /** Called before the request is sent. 360 356 * 361 * @param call Call structure with the request. 362 * @param phone Phone that the call will be sent through. 363 * 364 * @return Return 0 on success, ELIMIT or EPERM on error. 357 * @param call Call structure with the request. 358 * @param phone Phone that the call will be sent through. 359 * 360 * @return Return 0 on success, ELIMIT or EPERM on error. 361 * 365 362 */ 366 363 static int request_preprocess(call_t *call, phone_t *phone) 367 364 { 368 int newphid;369 size_t size;370 uintptr_t src;371 int rc;372 373 365 switch (IPC_GET_METHOD(call->data)) { 374 366 case IPC_M_CONNECTION_CLONE: { 375 367 phone_t *cloned_phone; 376 GET_CHECK_PHONE(cloned_phone, IPC_GET_ARG1(call->data), 377 return ENOENT;); 368 if (phone_get(IPC_GET_ARG1(call->data), &cloned_phone) != EOK) 369 return ENOENT; 370 378 371 phones_lock(cloned_phone, phone); 372 379 373 if ((cloned_phone->state != IPC_PHONE_CONNECTED) || 380 374 phone->state != IPC_PHONE_CONNECTED) { … … 382 376 return EINVAL; 383 377 } 378 384 379 /* 385 380 * We can be pretty sure now that both tasks exist and we are … … 387 382 * we are effectively preventing them from finishing their 388 383 * potential cleanup. 384 * 389 385 */ 390 newphid = phone_alloc(phone->callee->task);386 int newphid = phone_alloc(phone->callee->task); 391 387 if (newphid < 0) { 392 388 phones_unlock(cloned_phone, phone); 393 389 return ELIMIT; 394 390 } 391 395 392 ipc_phone_connect(&phone->callee->task->phones[newphid], 396 393 cloned_phone->callee); 397 394 phones_unlock(cloned_phone, phone); 395 398 396 /* Set the new phone for the callee. */ 399 397 IPC_SET_ARG1(call->data, newphid); … … 403 401 IPC_SET_ARG5(call->data, (unative_t) phone); 404 402 break; 405 case IPC_M_CONNECT_ME_TO: 406 newphid = phone_alloc(TASK);403 case IPC_M_CONNECT_ME_TO: { 404 int newphid = phone_alloc(TASK); 407 405 if (newphid < 0) 408 406 return ELIMIT; 407 409 408 /* Set arg5 for server */ 410 409 IPC_SET_ARG5(call->data, (unative_t) &TASK->phones[newphid]); … … 412 411 call->priv = newphid; 413 412 break; 414 case IPC_M_SHARE_OUT: 415 size = as_area_get_size(IPC_GET_ARG1(call->data)); 413 } 414 case IPC_M_SHARE_OUT: { 415 size_t size = as_area_get_size(IPC_GET_ARG1(call->data)); 416 416 if (!size) 417 417 return EPERM; 418 418 419 IPC_SET_ARG2(call->data, size); 419 420 break; 420 case IPC_M_DATA_READ: 421 size = IPC_GET_ARG2(call->data); 421 } 422 case IPC_M_DATA_READ: { 423 size_t size = IPC_GET_ARG2(call->data); 422 424 if ((size <= 0 || (size > DATA_XFER_LIMIT))) 423 425 return ELIMIT; 426 424 427 break; 425 case IPC_M_DATA_WRITE: 426 src = IPC_GET_ARG1(call->data); 427 size = IPC_GET_ARG2(call->data); 428 } 429 case IPC_M_DATA_WRITE: { 430 uintptr_t src = IPC_GET_ARG1(call->data); 431 size_t size = IPC_GET_ARG2(call->data); 428 432 429 433 if (size > DATA_XFER_LIMIT) … … 431 435 432 436 call->buffer = (uint8_t *) malloc(size, 0); 433 rc = copy_from_uspace(call->buffer, (void *) src, size);437 int rc = copy_from_uspace(call->buffer, (void *) src, size); 434 438 if (rc != 0) { 435 439 free(call->buffer); 436 440 return rc; 437 441 } 442 438 443 break; 444 } 439 445 #ifdef CONFIG_UDEBUG 440 446 case IPC_M_DEBUG_ALL: … … 444 450 break; 445 451 } 452 446 453 return 0; 447 454 } … … 453 460 /** Do basic kernel processing of received call answer. 454 461 * 455 * @param call Call structure with the answer. 462 * @param call Call structure with the answer. 463 * 456 464 */ 457 465 static void process_answer(call_t *call) … … 460 468 (call->flags & IPC_CALL_FORWARDED)) 461 469 IPC_SET_RETVAL(call->data, EFORWARD); 462 470 463 471 if (call->flags & IPC_CALL_CONN_ME_TO) { 464 472 if (IPC_GET_RETVAL(call->data)) … … 467 475 IPC_SET_ARG5(call->data, call->priv); 468 476 } 469 477 470 478 if (call->buffer) { 471 /* This must be an affirmative answer to IPC_M_DATA_READ. */ 472 /* or IPC_M_DEBUG_ALL/UDEBUG_M_MEM_READ... */ 479 /* 480 * This must be an affirmative answer to IPC_M_DATA_READ 481 * or IPC_M_DEBUG_ALL/UDEBUG_M_MEM_READ... 482 * 483 */ 473 484 uintptr_t dst = IPC_GET_ARG1(call->data); 474 485 size_t size = IPC_GET_ARG2(call->data); … … 483 494 /** Do basic kernel processing of received call request. 484 495 * 485 * @param box Destination answerbox structure. 486 * @param call Call structure with the request. 487 * 488 * @return Return 0 if the call should be passed to userspace. 489 * Return -1 if the call should be ignored. 496 * @param box Destination answerbox structure. 497 * @param call Call structure with the request. 498 * 499 * @return 0 if the call should be passed to userspace. 500 * @return -1 if the call should be ignored. 501 * 490 502 */ 491 503 static int process_request(answerbox_t *box, call_t *call) 492 504 { 493 int phoneid;494 495 505 if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_TO_ME) { 496 phoneid = phone_alloc(TASK);506 int phoneid = phone_alloc(TASK); 497 507 if (phoneid < 0) { /* Failed to allocate phone */ 498 508 IPC_SET_RETVAL(call->data, ELIMIT); … … 500 510 return -1; 501 511 } 512 502 513 IPC_SET_ARG5(call->data, phoneid); 503 514 } 515 504 516 switch (IPC_GET_METHOD(call->data)) { 505 517 case IPC_M_DEBUG_ALL: … … 508 520 break; 509 521 } 522 510 523 return 0; 511 524 } … … 516 529 * the generic function (i.e. sys_ipc_call_sync_slow()). 517 530 * 518 * @param phoneid Phone handle for the call. 519 * @param method Method of the call. 520 * @param arg1 Service-defined payload argument. 521 * @param arg2 Service-defined payload argument. 522 * @param arg3 Service-defined payload argument. 523 * @param data Address of userspace structure where the reply call will 524 * be stored. 525 * 526 * @return Returns 0 on success. 527 * Return ENOENT if there is no such phone handle. 531 * @param phoneid Phone handle for the call. 532 * @param method Method of the call. 533 * @param arg1 Service-defined payload argument. 534 * @param arg2 Service-defined payload argument. 535 * @param arg3 Service-defined payload argument. 536 * @param data Address of userspace structure where the reply call will 537 * be stored. 538 * 539 * @return 0 on success. 540 * @return ENOENT if there is no such phone handle. 541 * 528 542 */ 529 543 unative_t sys_ipc_call_sync_fast(unative_t phoneid, unative_t method, 530 544 unative_t arg1, unative_t arg2, unative_t arg3, ipc_data_t *data) 531 545 { 532 call_t *call;533 546 phone_t *phone; 534 int res; 535 int rc; 536 537 GET_CHECK_PHONE(phone, phoneid, return ENOENT;); 538 539 call = ipc_call_alloc(0); 547 if (phone_get(phoneid, &phone) != EOK) 548 return ENOENT; 549 550 call_t *call = ipc_call_alloc(0); 540 551 IPC_SET_METHOD(call->data, method); 541 552 IPC_SET_ARG1(call->data, arg1); 542 553 IPC_SET_ARG2(call->data, arg2); 543 554 IPC_SET_ARG3(call->data, arg3); 555 544 556 /* 545 557 * To achieve deterministic behavior, zero out arguments that are beyond … … 548 560 IPC_SET_ARG4(call->data, 0); 549 561 IPC_SET_ARG5(call->data, 0); 550 551 if (!(res = request_preprocess(call, phone))) { 562 563 int res = request_preprocess(call, phone); 564 int rc; 565 566 if (!res) { 552 567 #ifdef CONFIG_UDEBUG 553 568 udebug_stoppable_begin(); … … 557 572 udebug_stoppable_end(); 558 573 #endif 574 559 575 if (rc != EOK) { 560 576 /* The call will be freed by ipc_cleanup(). */ 561 577 return rc; 562 578 } 579 563 580 process_answer(call); 564 565 } else {581 582 } else 566 583 IPC_SET_RETVAL(call->data, res); 567 }584 568 585 rc = STRUCT_TO_USPACE(&data->args, &call->data.args); 569 586 ipc_call_free(call); 570 587 if (rc != 0) 571 588 return rc; 572 589 573 590 return 0; 574 591 } … … 576 593 /** Make a synchronous IPC call allowing to transmit the entire payload. 577 594 * 578 * @param phoneid Phone handle for the call. 579 * @param question Userspace address of call data with the request. 580 * @param reply Userspace address of call data where to store the 581 * answer. 582 * 583 * @return Zero on success or an error code. 595 * @param phoneid Phone handle for the call. 596 * @param question Userspace address of call data with the request. 597 * @param reply Userspace address of call data where to store the 598 * answer. 599 * 600 * @return Zero on success or an error code. 601 * 584 602 */ 585 603 unative_t sys_ipc_call_sync_slow(unative_t phoneid, ipc_data_t *question, 586 604 ipc_data_t *reply) 587 605 { 588 call_t *call;589 606 phone_t *phone; 590 int res; 591 int rc; 592 593 GET_CHECK_PHONE(phone, phoneid, return ENOENT;); 594 595 call = ipc_call_alloc(0); 596 rc = copy_from_uspace(&call->data.args, &question->args, 607 if (phone_get(phoneid, &phone) != EOK) 608 return ENOENT; 609 610 call_t *call = ipc_call_alloc(0); 611 int rc = copy_from_uspace(&call->data.args, &question->args, 597 612 sizeof(call->data.args)); 598 613 if (rc != 0) { … … 600 615 return (unative_t) rc; 601 616 } 602 603 604 if (!(res = request_preprocess(call, phone))) { 617 618 int res = request_preprocess(call, phone); 619 620 if (!res) { 605 621 #ifdef CONFIG_UDEBUG 606 622 udebug_stoppable_begin(); … … 610 626 udebug_stoppable_end(); 611 627 #endif 628 612 629 if (rc != EOK) { 613 630 /* The call will be freed by ipc_cleanup(). */ 614 631 return rc; 615 632 } 633 616 634 process_answer(call); 617 } else 635 } else 618 636 IPC_SET_RETVAL(call->data, res); 619 637 620 638 rc = STRUCT_TO_USPACE(&reply->args, &call->data.args); 621 639 ipc_call_free(call); 622 640 if (rc != 0) 623 641 return rc; 624 642 625 643 return 0; 626 644 } … … 628 646 /** Check that the task did not exceed the allowed limit of asynchronous calls. 629 647 * 630 * @return Return 0 if limit not reached or -1 if limit exceeded. 648 * @return 0 if limit not reached or -1 if limit exceeded. 649 * 631 650 */ 632 651 static int check_call_limit(void) … … 636 655 return -1; 637 656 } 657 638 658 return 0; 639 659 } … … 644 664 * the generic function sys_ipc_call_async_slow(). 645 665 * 646 * @param phoneid Phone handle for the call. 647 * @param method Method of the call. 648 * @param arg1 Service-defined payload argument. 649 * @param arg2 Service-defined payload argument. 650 * @param arg3 Service-defined payload argument. 651 * @param arg4 Service-defined payload argument. 652 * 653 * @return Return call hash on success. 654 * Return IPC_CALLRET_FATAL in case of a fatal error and 655 * IPC_CALLRET_TEMPORARY if there are too many pending 656 * asynchronous requests; answers should be handled first. 666 * @param phoneid Phone handle for the call. 667 * @param method Method of the call. 668 * @param arg1 Service-defined payload argument. 669 * @param arg2 Service-defined payload argument. 670 * @param arg3 Service-defined payload argument. 671 * @param arg4 Service-defined payload argument. 672 * 673 * @return Call hash on success. 674 * @return IPC_CALLRET_FATAL in case of a fatal error. 675 * @return IPC_CALLRET_TEMPORARY if there are too many pending 676 * asynchronous requests; answers should be handled first. 677 * 657 678 */ 658 679 unative_t sys_ipc_call_async_fast(unative_t phoneid, unative_t method, 659 680 unative_t arg1, unative_t arg2, unative_t arg3, unative_t arg4) 660 681 { 661 call_t *call;662 phone_t *phone;663 int res;664 665 682 if (check_call_limit()) 666 683 return IPC_CALLRET_TEMPORARY; 667 668 GET_CHECK_PHONE(phone, phoneid, return IPC_CALLRET_FATAL;); 669 670 call = ipc_call_alloc(0); 684 685 phone_t *phone; 686 if (phone_get(phoneid, &phone) != EOK) 687 return IPC_CALLRET_FATAL; 688 689 call_t *call = ipc_call_alloc(0); 671 690 IPC_SET_METHOD(call->data, method); 672 691 IPC_SET_ARG1(call->data, arg1); … … 674 693 IPC_SET_ARG3(call->data, arg3); 675 694 IPC_SET_ARG4(call->data, arg4); 695 676 696 /* 677 697 * To achieve deterministic behavior, zero out arguments that are beyond … … 679 699 */ 680 700 IPC_SET_ARG5(call->data, 0); 681 682 if (!(res = request_preprocess(call, phone))) 701 702 int res = request_preprocess(call, phone); 703 704 if (!res) 683 705 ipc_call(phone, call); 684 706 else 685 707 ipc_backsend_err(phone, call, res); 686 708 687 709 return (unative_t) call; 688 710 } … … 690 712 /** Make an asynchronous IPC call allowing to transmit the entire payload. 691 713 * 692 * @param phoneid Phone handle for the call. 693 * @param data Userspace address of call data with the request. 694 * 695 * @return See sys_ipc_call_async_fast(). 714 * @param phoneid Phone handle for the call. 715 * @param data Userspace address of call data with the request. 716 * 717 * @return See sys_ipc_call_async_fast(). 718 * 696 719 */ 697 720 unative_t sys_ipc_call_async_slow(unative_t phoneid, ipc_data_t *data) 698 721 { 699 call_t *call;700 phone_t *phone;701 int res;702 int rc;703 704 722 if (check_call_limit()) 705 723 return IPC_CALLRET_TEMPORARY; 706 707 GET_CHECK_PHONE(phone, phoneid, return IPC_CALLRET_FATAL;); 708 709 call = ipc_call_alloc(0); 710 rc = copy_from_uspace(&call->data.args, &data->args, 724 725 phone_t *phone; 726 if (phone_get(phoneid, &phone) != EOK) 727 return IPC_CALLRET_FATAL; 728 729 call_t *call = ipc_call_alloc(0); 730 int rc = copy_from_uspace(&call->data.args, &data->args, 711 731 sizeof(call->data.args)); 712 732 if (rc != 0) { … … 714 734 return (unative_t) rc; 715 735 } 716 if (!(res = request_preprocess(call, phone))) 736 737 int res = request_preprocess(call, phone); 738 739 if (!res) 717 740 ipc_call(phone, call); 718 741 else 719 742 ipc_backsend_err(phone, call, res); 720 743 721 744 return (unative_t) call; 722 745 } 723 746 724 /** Forward a received call to another destination - common code for both the 725 * fast and the slow version. 726 * 727 * @param callid Hash of the call to forward. 728 * @param phoneid Phone handle to use for forwarding. 729 * @param method New method to use for the forwarded call. 730 * @param arg1 New value of the first argument for the forwarded call. 731 * @param arg2 New value of the second argument for the forwarded call. 732 * @param arg3 New value of the third argument for the forwarded call. 733 * @param arg4 New value of the fourth argument for the forwarded call. 734 * @param arg5 New value of the fifth argument for the forwarded call. 735 * @param mode Flags that specify mode of the forward operation. 736 * @param slow If true, arg3, arg4 and arg5 are considered. Otherwise 737 * the function considers only the fast version arguments: 738 * i.e. arg1 and arg2. 739 * 740 * @return Return 0 on succes, otherwise return an error code. 741 * 742 * Warning: Make sure that ARG5 is not rewritten for certain system IPC 747 /** Forward a received call to another destination 748 * 749 * Common code for both the fast and the slow version. 750 * 751 * @param callid Hash of the call to forward. 752 * @param phoneid Phone handle to use for forwarding. 753 * @param method New method to use for the forwarded call. 754 * @param arg1 New value of the first argument for the forwarded call. 755 * @param arg2 New value of the second argument for the forwarded call. 756 * @param arg3 New value of the third argument for the forwarded call. 757 * @param arg4 New value of the fourth argument for the forwarded call. 758 * @param arg5 New value of the fifth argument for the forwarded call. 759 * @param mode Flags that specify mode of the forward operation. 760 * @param slow If true, arg3, arg4 and arg5 are considered. Otherwise 761 * the function considers only the fast version arguments: 762 * i.e. arg1 and arg2. 763 * 764 * @return 0 on succes, otherwise an error code. 765 * 766 * Warning: Make sure that ARG5 is not rewritten for certain system IPC 767 * 743 768 */ 744 769 static unative_t sys_ipc_forward_common(unative_t callid, unative_t phoneid, 745 770 unative_t method, unative_t arg1, unative_t arg2, unative_t arg3, 746 unative_t arg4, unative_t arg5, int mode, bool slow) 747 { 748 call_t *call; 749 phone_t *phone; 750 751 call = get_call(callid); 771 unative_t arg4, unative_t arg5, unsigned int mode, bool slow) 772 { 773 call_t *call = get_call(callid); 752 774 if (!call) 753 775 return ENOENT; 754 776 755 777 call->flags |= IPC_CALL_FORWARDED; 756 757 GET_CHECK_PHONE(phone, phoneid, { 778 779 phone_t *phone; 780 if (phone_get(phoneid, &phone) != EOK) { 758 781 IPC_SET_RETVAL(call->data, EFORWARD); 759 782 ipc_answer(&TASK->answerbox, call); 760 783 return ENOENT; 761 } );762 784 } 785 763 786 if (!method_is_forwardable(IPC_GET_METHOD(call->data))) { 764 787 IPC_SET_RETVAL(call->data, EFORWARD); … … 766 789 return EPERM; 767 790 } 768 791 769 792 /* 770 793 * Userspace is not allowed to change method of system methods on … … 777 800 if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_TO_ME) 778 801 phone_dealloc(IPC_GET_ARG5(call->data)); 779 802 780 803 IPC_SET_ARG1(call->data, method); 781 804 IPC_SET_ARG2(call->data, arg1); 782 805 IPC_SET_ARG3(call->data, arg2); 806 783 807 if (slow) { 784 808 IPC_SET_ARG4(call->data, arg3); … … 799 823 } 800 824 } 801 825 802 826 return ipc_forward(call, phone, &TASK->answerbox, mode); 803 827 } 804 828 805 829 /** Forward a received call to another destination - fast version. 806 *807 * @param callid Hash of the call to forward.808 * @param phoneid Phone handle to use for forwarding.809 * @param method New method to use for the forwarded call.810 * @param arg1 New value of the first argument for the forwarded call.811 * @param arg2 New value of the second argument for the forwarded call.812 * @param mode Flags that specify mode of the forward operation.813 *814 * @return Return 0 on succes, otherwise return an error code.815 830 * 816 831 * In case the original method is a system method, ARG1, ARG2 and ARG3 are … … 820 835 * is a set of immutable methods, for which the new method and arguments are not 821 836 * set and these values are ignored. 837 * 838 * @param callid Hash of the call to forward. 839 * @param phoneid Phone handle to use for forwarding. 840 * @param method New method to use for the forwarded call. 841 * @param arg1 New value of the first argument for the forwarded call. 842 * @param arg2 New value of the second argument for the forwarded call. 843 * @param mode Flags that specify mode of the forward operation. 844 * 845 * @return 0 on succes, otherwise an error code. 846 * 822 847 */ 823 848 unative_t sys_ipc_forward_fast(unative_t callid, unative_t phoneid, 824 unative_t method, unative_t arg1, unative_t arg2, int mode)849 unative_t method, unative_t arg1, unative_t arg2, unsigned int mode) 825 850 { 826 851 return sys_ipc_forward_common(callid, phoneid, method, arg1, arg2, 0, 0, … … 829 854 830 855 /** Forward a received call to another destination - slow version. 831 *832 * @param callid Hash of the call to forward.833 * @param phoneid Phone handle to use for forwarding.834 * @param data Userspace address of the new IPC data.835 * @param mode Flags that specify mode of the forward operation.836 *837 * @return Return 0 on succes, otherwise return an error code.838 856 * 839 857 * This function is the slow verision of the sys_ipc_forward_fast interface. … … 843 861 * methods, it additionally stores the new value of arg3, arg4 and arg5, 844 862 * respectively, to ARG3, ARG4 and ARG5, respectively. 863 * 864 * @param callid Hash of the call to forward. 865 * @param phoneid Phone handle to use for forwarding. 866 * @param data Userspace address of the new IPC data. 867 * @param mode Flags that specify mode of the forward operation. 868 * 869 * @return 0 on succes, otherwise an error code. 870 * 845 871 */ 846 872 unative_t sys_ipc_forward_slow(unative_t callid, unative_t phoneid, 847 ipc_data_t *data, int mode)873 ipc_data_t *data, unsigned int mode) 848 874 { 849 875 ipc_data_t newdata; 850 int rc; 851 852 rc = copy_from_uspace(&newdata.args, &data->args, 876 int rc = copy_from_uspace(&newdata.args, &data->args, 853 877 sizeof(newdata.args)); 854 if (rc != 0) 878 if (rc != 0) 855 879 return (unative_t) rc; 856 880 857 881 return sys_ipc_forward_common(callid, phoneid, 858 882 IPC_GET_METHOD(newdata), IPC_GET_ARG1(newdata), … … 866 890 * than the generic sys_ipc_answer(). 867 891 * 868 * @param callid Hash of the call to be answered. 869 * @param retval Return value of the answer. 870 * @param arg1 Service-defined return value. 871 * @param arg2 Service-defined return value. 872 * @param arg3 Service-defined return value. 873 * @param arg4 Service-defined return value. 874 * 875 * @return Return 0 on success, otherwise return an error code. 892 * @param callid Hash of the call to be answered. 893 * @param retval Return value of the answer. 894 * @param arg1 Service-defined return value. 895 * @param arg2 Service-defined return value. 896 * @param arg3 Service-defined return value. 897 * @param arg4 Service-defined return value. 898 * 899 * @return 0 on success, otherwise an error code. 900 * 876 901 */ 877 902 unative_t sys_ipc_answer_fast(unative_t callid, unative_t retval, 878 903 unative_t arg1, unative_t arg2, unative_t arg3, unative_t arg4) 879 904 { 880 call_t *call;881 ipc_data_t saved_data;882 int saveddata = 0;883 int rc;884 885 905 /* Do not answer notification callids */ 886 906 if (callid & IPC_CALLID_NOTIFICATION) 887 907 return 0; 888 889 call = get_call(callid);908 909 call_t *call = get_call(callid); 890 910 if (!call) 891 911 return ENOENT; 892 912 913 ipc_data_t saved_data; 914 bool saved; 915 893 916 if (answer_need_old(call)) { 894 917 memcpy(&saved_data, &call->data, sizeof(call->data)); 895 saveddata = 1; 896 } 897 918 saved = true; 919 } else 920 saved = false; 921 898 922 IPC_SET_RETVAL(call->data, retval); 899 923 IPC_SET_ARG1(call->data, arg1); … … 901 925 IPC_SET_ARG3(call->data, arg3); 902 926 IPC_SET_ARG4(call->data, arg4); 927 903 928 /* 904 929 * To achieve deterministic behavior, zero out arguments that are beyond … … 906 931 */ 907 932 IPC_SET_ARG5(call->data, 0); 908 rc = answer_preprocess(call, saveddata? &saved_data : NULL);909 933 int rc = answer_preprocess(call, saved ? &saved_data : NULL); 934 910 935 ipc_answer(&TASK->answerbox, call); 911 936 return rc; … … 914 939 /** Answer an IPC call. 915 940 * 916 * @param callid Hash of the call to be answered. 917 * @param data Userspace address of call data with the answer. 918 * 919 * @return Return 0 on success, otherwise return an error code. 941 * @param callid Hash of the call to be answered. 942 * @param data Userspace address of call data with the answer. 943 * 944 * @return 0 on success, otherwise an error code. 945 * 920 946 */ 921 947 unative_t sys_ipc_answer_slow(unative_t callid, ipc_data_t *data) 922 948 { 923 call_t *call;924 ipc_data_t saved_data;925 int saveddata = 0;926 int rc;927 928 949 /* Do not answer notification callids */ 929 950 if (callid & IPC_CALLID_NOTIFICATION) 930 951 return 0; 931 932 call = get_call(callid);952 953 call_t *call = get_call(callid); 933 954 if (!call) 934 955 return ENOENT; 935 956 957 ipc_data_t saved_data; 958 bool saved; 959 936 960 if (answer_need_old(call)) { 937 961 memcpy(&saved_data, &call->data, sizeof(call->data)); 938 saveddata = 1; 939 } 940 rc = copy_from_uspace(&call->data.args, &data->args, 962 saved = true; 963 } else 964 saved = false; 965 966 int rc = copy_from_uspace(&call->data.args, &data->args, 941 967 sizeof(call->data.args)); 942 968 if (rc != 0) 943 969 return rc; 944 945 rc = answer_preprocess(call, saved data? &saved_data : NULL);970 971 rc = answer_preprocess(call, saved ? &saved_data : NULL); 946 972 947 973 ipc_answer(&TASK->answerbox, call); 948 949 974 return rc; 950 975 } … … 952 977 /** Hang up a phone. 953 978 * 954 * @param Phone handle of the phone to be hung up. 955 * 956 * @return Return 0 on success or an error code. 957 */ 958 unative_t sys_ipc_hangup(int phoneid) 979 * @param Phone handle of the phone to be hung up. 980 * 981 * @return 0 on success or an error code. 982 * 983 */ 984 unative_t sys_ipc_hangup(unative_t phoneid) 959 985 { 960 986 phone_t *phone; 961 962 GET_CHECK_PHONE(phone, phoneid, return ENOENT;); 963 987 988 if (phone_get(phoneid, &phone) != EOK) 989 return ENOENT; 990 964 991 if (ipc_phone_hangup(phone)) 965 992 return -1; 966 993 967 994 return 0; 968 995 } … … 970 997 /** Wait for an incoming IPC call or an answer. 971 998 * 972 * @param calldata Pointer to buffer where the call/answer data is stored. 973 * @param usec Timeout. See waitq_sleep_timeout() for explanation. 974 * @param flags Select mode of sleep operation. See waitq_sleep_timeout() 975 * for explanation. 976 * 977 * @return Hash of the call. 978 * If IPC_CALLID_NOTIFICATION bit is set in the hash, the 979 * call is a notification. IPC_CALLID_ANSWERED denotes an 980 * answer. 981 */ 982 unative_t sys_ipc_wait_for_call(ipc_data_t *calldata, uint32_t usec, int flags) 999 * @param calldata Pointer to buffer where the call/answer data is stored. 1000 * @param usec Timeout. See waitq_sleep_timeout() for explanation. 1001 * @param flags Select mode of sleep operation. See waitq_sleep_timeout() 1002 * for explanation. 1003 * 1004 * @return Hash of the call. 1005 * If IPC_CALLID_NOTIFICATION bit is set in the hash, the 1006 * call is a notification. IPC_CALLID_ANSWERED denotes an 1007 * answer. 1008 * 1009 */ 1010 unative_t sys_ipc_wait_for_call(ipc_data_t *calldata, uint32_t usec, 1011 unsigned int flags) 983 1012 { 984 1013 call_t *call; 985 1014 986 1015 restart: 987 1016 988 1017 #ifdef CONFIG_UDEBUG 989 1018 udebug_stoppable_begin(); 990 #endif 1019 #endif 1020 991 1021 call = ipc_wait_for_call(&TASK->answerbox, usec, 992 1022 flags | SYNCH_FLAGS_INTERRUPTIBLE); 993 1023 994 1024 #ifdef CONFIG_UDEBUG 995 1025 udebug_stoppable_end(); 996 1026 #endif 1027 997 1028 if (!call) 998 1029 return 0; 999 1030 1000 1031 if (call->flags & IPC_CALL_NOTIF) { 1001 1032 /* Set in_phone_hash to the interrupt counter */ … … 1003 1034 1004 1035 STRUCT_TO_USPACE(calldata, &call->data); 1005 1036 1006 1037 ipc_call_free(call); 1007 1038 1008 1039 return ((unative_t) call) | IPC_CALLID_NOTIFICATION; 1009 1040 } 1010 1041 1011 1042 if (call->flags & IPC_CALL_ANSWERED) { 1012 1043 process_answer(call); 1013 1044 1014 1045 if (call->flags & IPC_CALL_DISCARD_ANSWER) { 1015 1046 ipc_call_free(call); … … 1023 1054 atomic_dec(&TASK->active_calls); 1024 1055 } 1025 1056 1026 1057 STRUCT_TO_USPACE(&calldata->args, &call->data.args); 1027 1058 ipc_call_free(call); 1028 1059 1029 1060 return ((unative_t) call) | IPC_CALLID_ANSWERED; 1030 1061 } 1031 1062 1032 1063 if (process_request(&TASK->answerbox, call)) 1033 1064 goto restart; 1034 1065 1035 1066 /* Include phone address('id') of the caller in the request, 1036 1067 * copy whole call->data, not only call->data.args */ … … 1041 1072 */ 1042 1073 ipc_data_t saved_data; 1043 int saveddata = 0;1044 1074 bool saved; 1075 1045 1076 if (answer_need_old(call)) { 1046 1077 memcpy(&saved_data, &call->data, sizeof(call->data)); 1047 saveddata = 1; 1048 } 1078 saved = true; 1079 } else 1080 saved = false; 1049 1081 1050 1082 IPC_SET_RETVAL(call->data, EPARTY); 1051 (void) answer_preprocess(call, saved data? &saved_data : NULL);1083 (void) answer_preprocess(call, saved ? &saved_data : NULL); 1052 1084 ipc_answer(&TASK->answerbox, call); 1053 1085 return 0; 1054 1086 } 1055 return (unative_t)call; 1056 } 1057 1058 /** Interrupt one thread from sys_ipc_wait_for_call(). */ 1087 1088 return (unative_t) call; 1089 } 1090 1091 /** Interrupt one thread from sys_ipc_wait_for_call(). 1092 * 1093 */ 1059 1094 unative_t sys_ipc_poke(void) 1060 1095 { 1061 waitq_unsleep(&TASK->answerbox.wq); 1096 waitq_unsleep(&TASK->answerbox.wq); 1062 1097 return EOK; 1063 1098 } … … 1065 1100 /** Connect an IRQ handler to a task. 1066 1101 * 1067 * @param inr IRQ number. 1068 * @param devno Device number. 1069 * @param method Method to be associated with the notification. 1070 * @param ucode Uspace pointer to the top-half pseudocode. 1071 * 1072 * @return EPERM or a return code returned by ipc_irq_register(). 1102 * @param inr IRQ number. 1103 * @param devno Device number. 1104 * @param method Method to be associated with the notification. 1105 * @param ucode Uspace pointer to the top-half pseudocode. 1106 * 1107 * @return EPERM or a return code returned by ipc_irq_register(). 1108 * 1073 1109 */ 1074 1110 unative_t sys_ipc_register_irq(inr_t inr, devno_t devno, unative_t method, … … 1077 1113 if (!(cap_get(TASK) & CAP_IRQ_REG)) 1078 1114 return EPERM; 1079 1115 1080 1116 return ipc_irq_register(&TASK->answerbox, inr, devno, method, ucode); 1081 1117 } … … 1083 1119 /** Disconnect an IRQ handler from a task. 1084 1120 * 1085 * @param inr IRQ number. 1086 * @param devno Device number. 1087 * 1088 * @return Zero on success or EPERM on error.. 1121 * @param inr IRQ number. 1122 * @param devno Device number. 1123 * 1124 * @return Zero on success or EPERM on error. 1125 * 1089 1126 */ 1090 1127 unative_t sys_ipc_unregister_irq(inr_t inr, devno_t devno) … … 1092 1129 if (!(cap_get(TASK) & CAP_IRQ_REG)) 1093 1130 return EPERM; 1094 1131 1095 1132 ipc_irq_unregister(&TASK->answerbox, inr, devno); 1096 1133 1097 1134 return 0; 1098 1135 } … … 1100 1137 #include <console/console.h> 1101 1138 1102 /** 1103 * Syscall connect to a task by id.1104 * 1105 * @return Phone id on success, or negative error code.1139 /** Syscall connect to a task by id. 1140 * 1141 * @return Phone id on success, or negative error code. 1142 * 1106 1143 */ 1107 1144 unative_t sys_ipc_connect_kbox(sysarg64_t *uspace_taskid_arg) … … 1109 1146 #ifdef CONFIG_UDEBUG 1110 1147 sysarg64_t taskid_arg; 1111 int rc; 1112 1113 rc = copy_from_uspace(&taskid_arg, uspace_taskid_arg, sizeof(sysarg64_t)); 1148 int rc = copy_from_uspace(&taskid_arg, uspace_taskid_arg, sizeof(sysarg64_t)); 1114 1149 if (rc != 0) 1115 1150 return (unative_t) rc; 1116 1117 LOG("sys_ipc_connect_kbox(%" PRIu64 ") \n", taskid_arg.value);1118 1151 1152 LOG("sys_ipc_connect_kbox(%" PRIu64 ")", taskid_arg.value); 1153 1119 1154 return ipc_connect_kbox(taskid_arg.value); 1120 1155 #else
Note:
See TracChangeset
for help on using the changeset viewer.
