Changeset c07544d3 in mainline for uspace/lib/libc/generic/async.c
- Timestamp:
- 2009-04-24T15:38:18Z (16 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 10270a8
- Parents:
- 422fd81
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/libc/generic/async.c
r422fd81 rc07544d3 31 31 */ 32 32 /** @file 33 */ 33 */ 34 34 35 35 /** 36 36 * Asynchronous library 37 37 * 38 * The aim of this library is facilitating writing programs utilizing the 39 * asynchronous nature of HelenOS IPC, yet using a normal way of programming. 38 * The aim of this library is to provide a facility for writing programs which 39 * utilize the asynchronous nature of HelenOS IPC, yet using a normal way of 40 * programming. 40 41 * 41 42 * You should be able to write very simple multithreaded programs, the async … … 43 44 * 44 45 * Default semantics: 45 * - async_send_*(): send asynchronously. If the kernel refuses to send46 * 47 * 46 * - async_send_*(): Send asynchronously. If the kernel refuses to send 47 * more messages, [ try to get responses from kernel, if 48 * nothing found, might try synchronous ] 48 49 * 49 50 * Example of use (pseudo C): 50 * 51 * 51 52 * 1) Multithreaded client application 52 53 * 53 * fibril_create(fibril1, ...);54 * fibril_create(fibril2, ...);55 * ...56 * 57 * int fibril1(void *arg)58 * {59 * 60 * 61 * 62 * 63 * 64 * 65 * }54 * fibril_create(fibril1, ...); 55 * fibril_create(fibril2, ...); 56 * ... 57 * 58 * int fibril1(void *arg) 59 * { 60 * conn = ipc_connect_me_to(); 61 * c1 = async_send(conn); 62 * c2 = async_send(conn); 63 * async_wait_for(c1); 64 * async_wait_for(c2); 65 * ... 66 * } 66 67 * 67 68 * 68 69 * 2) Multithreaded server application 69 * main()70 * {71 * async_manager();72 * }73 * 74 * 75 * my_client_connection(icallid, *icall)76 * {77 * 78 * 79 * 80 * 81 * 82 * 83 * 84 * 85 * 86 * 87 * 88 * ....89 * }70 * 71 * main() 72 * { 73 * async_manager(); 74 * } 75 * 76 * my_client_connection(icallid, *icall) 77 * { 78 * if (want_refuse) { 79 * ipc_answer_0(icallid, ELIMIT); 80 * return; 81 * } 82 * ipc_answer_0(icallid, EOK); 83 * 84 * callid = async_get_call(&call); 85 * handle_call(callid, call); 86 * ipc_answer_2(callid, 1, 2, 3); 87 * 88 * callid = async_get_call(&call); 89 * ... 90 * } 90 91 * 91 92 */ … … 105 106 106 107 atomic_t async_futex = FUTEX_INITIALIZER; 107 static hash_table_t conn_hash_table;108 static LIST_INITIALIZE(timeout_list);109 108 110 109 /** Structures of this type represent a waiting fibril. */ 111 110 typedef struct { 112 111 /** Expiration time. */ 113 struct timeval expires; 112 struct timeval expires; 113 114 114 /** If true, this struct is in the timeout list. */ 115 int inlist; 115 bool inlist; 116 116 117 /** Timeout list link. */ 117 118 link_t link; 118 119 119 120 /** Identification of and link to the waiting fibril. */ 120 121 fid_t fid; 122 121 123 /** If true, this fibril is currently active. */ 122 int active; 124 bool active; 125 123 126 /** If true, we have timed out. */ 124 inttimedout;127 bool timedout; 125 128 } awaiter_t; 126 129 … … 129 132 130 133 /** If reply was received. */ 131 int done; 134 bool done; 135 132 136 /** Pointer to where the answer data is stored. */ 133 134 137 ipc_call_t *dataptr; 138 135 139 ipcarg_t retval; 136 140 } amsg_t; … … 148 152 typedef struct { 149 153 awaiter_t wdata; 150 154 151 155 /** Hash table link. */ 152 156 link_t link; 153 157 154 158 /** Incoming phone hash. */ 155 ipcarg_t in_phone_hash; 156 159 ipcarg_t in_phone_hash; 160 157 161 /** Messages that should be delivered to this fibril. */ 158 link_t msg_queue; 159 162 link_t msg_queue; 163 160 164 /** Identification of the opening call. */ 161 165 ipc_callid_t callid; 162 166 /** Call data of the opening call. */ 163 167 ipc_call_t call; 164 168 165 169 /** Identification of the closing call. */ 166 170 ipc_callid_t close_callid; 167 171 168 172 /** Fibril function that will be used to handle the connection. */ 169 173 void (*cfibril)(ipc_callid_t, ipc_call_t *); … … 173 177 __thread connection_t *FIBRIL_connection; 174 178 175 /**176 * If true, it is forbidden to use async_req functions and all preemption is177 * disabled.178 */179 __thread int _in_interrupt_handler;180 181 179 static void default_client_connection(ipc_callid_t callid, ipc_call_t *call); 182 180 static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call); … … 186 184 */ 187 185 static async_client_conn_t client_connection = default_client_connection; 186 188 187 /** 189 188 * Pointer to a fibril function that will be used to handle interrupt … … 192 191 static async_client_conn_t interrupt_received = default_interrupt_received; 193 192 194 /* 195 * Getter for _in_interrupt_handler. We need to export the value of this thread 196 * local variable to other modules, but the binutils 2.18 linkers die on an 197 * attempt to export this symbol in the header file. For now, consider this as a 198 * workaround. 199 */ 200 bool in_interrupt_handler(void) 201 { 202 return _in_interrupt_handler; 203 } 204 205 #define CONN_HASH_TABLE_CHAINS 32 193 194 static hash_table_t conn_hash_table; 195 static LIST_INITIALIZE(timeout_list); 196 197 198 #define CONN_HASH_TABLE_CHAINS 32 206 199 207 200 /** Compute hash into the connection hash table based on the source phone hash. 208 201 * 209 * @param key Pointer to source phone hash. 210 * 211 * @return Index into the connection hash table. 202 * @param key Pointer to source phone hash. 203 * 204 * @return Index into the connection hash table. 205 * 212 206 */ 213 207 static hash_index_t conn_hash(unsigned long *key) 214 208 { 215 209 assert(key); 216 return (( *key) >> 4) % CONN_HASH_TABLE_CHAINS;210 return (((*key) >> 4) % CONN_HASH_TABLE_CHAINS); 217 211 } 218 212 219 213 /** Compare hash table item with a key. 220 214 * 221 * @param key Array containing the source phone hash as the only item. 222 * @param keys Expected 1 but ignored. 223 * @param item Connection hash table item. 224 * 225 * @return True on match, false otherwise. 215 * @param key Array containing the source phone hash as the only item. 216 * @param keys Expected 1 but ignored. 217 * @param item Connection hash table item. 218 * 219 * @return True on match, false otherwise. 220 * 226 221 */ 227 222 static int conn_compare(unsigned long key[], hash_count_t keys, link_t *item) 228 223 { 229 connection_t *hs; 230 231 hs = hash_table_get_instance(item, connection_t, link); 232 233 return key[0] == hs->in_phone_hash; 224 connection_t *hs = hash_table_get_instance(item, connection_t, link); 225 return (key[0] == hs->in_phone_hash); 234 226 } 235 227 … … 239 231 * hash table. 240 232 * 241 * @param item Connection hash table item being removed. 233 * @param item Connection hash table item being removed. 234 * 242 235 */ 243 236 static void conn_remove(link_t *item) … … 256 249 /** Sort in current fibril's timeout request. 257 250 * 258 * @param wd Wait data of the current fibril. 251 * @param wd Wait data of the current fibril. 252 * 259 253 */ 260 254 static void insert_timeout(awaiter_t *wd) 261 255 { 262 link_t *tmp; 263 awaiter_t *cur; 264 265 wd->timedout = 0; 266 wd->inlist = 1; 267 268 tmp = timeout_list.next; 256 wd->timedout = false; 257 wd->inlist = true; 258 259 link_t *tmp = timeout_list.next; 269 260 while (tmp != &timeout_list) { 270 cur = list_get_instance(tmp, awaiter_t, link); 261 awaiter_t *cur = list_get_instance(tmp, awaiter_t, link); 262 271 263 if (tv_gteq(&cur->expires, &wd->expires)) 272 264 break; 265 273 266 tmp = tmp->next; 274 267 } 268 275 269 list_append(&wd->link, tmp); 276 270 } … … 282 276 * timeouts are unregistered. 283 277 * 284 * @param callid Hash of the incoming call. 285 * @param call Data of the incoming call. 286 * 287 * @return Zero if the call doesn't match any connection. 288 * One if the call was passed to the respective connection 289 * fibril. 290 */ 291 static int route_call(ipc_callid_t callid, ipc_call_t *call) 292 { 293 connection_t *conn; 294 msg_t *msg; 295 link_t *hlp; 296 unsigned long key; 297 278 * @param callid Hash of the incoming call. 279 * @param call Data of the incoming call. 280 * 281 * @return False if the call doesn't match any connection. 282 * True if the call was passed to the respective connection fibril. 283 * 284 */ 285 static bool route_call(ipc_callid_t callid, ipc_call_t *call) 286 { 298 287 futex_down(&async_futex); 299 300 key = call->in_phone_hash; 301 hlp = hash_table_find(&conn_hash_table, &key); 288 289 unsigned long key = call->in_phone_hash; 290 link_t *hlp = hash_table_find(&conn_hash_table, &key); 291 302 292 if (!hlp) { 303 293 futex_up(&async_futex); 304 return 0; 305 } 306 conn = hash_table_get_instance(hlp, connection_t, link); 307 308 msg = malloc(sizeof(*msg)); 294 return false; 295 } 296 297 connection_t *conn = hash_table_get_instance(hlp, connection_t, link); 298 299 msg_t *msg = malloc(sizeof(*msg)); 300 if (!msg) { 301 futex_up(&async_futex); 302 return false; 303 } 304 309 305 msg->callid = callid; 310 306 msg->call = *call; 311 307 list_append(&msg->link, &conn->msg_queue); 312 308 313 309 if (IPC_GET_METHOD(*call) == IPC_M_PHONE_HUNGUP) 314 310 conn->close_callid = callid; … … 316 312 /* If the connection fibril is waiting for an event, activate it */ 317 313 if (!conn->wdata.active) { 314 318 315 /* If in timeout list, remove it */ 319 316 if (conn->wdata.inlist) { 320 conn->wdata.inlist = 0;317 conn->wdata.inlist = false; 321 318 list_remove(&conn->wdata.link); 322 319 } 323 conn->wdata.active = 1; 320 321 conn->wdata.active = true; 324 322 fibril_add_ready(conn->wdata.fid); 325 323 } 326 324 327 325 futex_up(&async_futex); 328 329 return 1; 326 return true; 327 } 328 329 /** Notification fibril. 330 * 331 * When a notification arrives, a fibril with this implementing function is 332 * created. It calls interrupt_received() and does the final cleanup. 333 * 334 * @param arg Message structure pointer. 335 * 336 * @return Always zero. 337 * 338 */ 339 static int notification_fibril(void *arg) 340 { 341 msg_t *msg = (msg_t *) arg; 342 interrupt_received(msg->callid, &msg->call); 343 344 free(msg); 345 return 0; 346 } 347 348 /** Process interrupt notification. 349 * 350 * A new fibril is created which would process the notification. 351 * 352 * @param callid Hash of the incoming call. 353 * @param call Data of the incoming call. 354 * 355 * @return False if an error occured. 356 * True if the call was passed to the notification fibril. 357 * 358 */ 359 static bool process_notification(ipc_callid_t callid, ipc_call_t *call) 360 { 361 futex_down(&async_futex); 362 363 msg_t *msg = malloc(sizeof(*msg)); 364 if (!msg) { 365 futex_up(&async_futex); 366 return false; 367 } 368 369 msg->callid = callid; 370 msg->call = *call; 371 372 fid_t fid = fibril_create(notification_fibril, msg); 373 fibril_add_ready(fid); 374 375 futex_up(&async_futex); 376 return true; 330 377 } 331 378 332 379 /** Return new incoming message for the current (fibril-local) connection. 333 380 * 334 * @param call Storage where the incoming call data will be stored. 335 * @param usecs Timeout in microseconds. Zero denotes no timeout. 336 * 337 * @return If no timeout was specified, then a hash of the 338 * incoming call is returned. If a timeout is specified, 339 * then a hash of the incoming call is returned unless 340 * the timeout expires prior to receiving a message. In 341 * that case zero is returned. 381 * @param call Storage where the incoming call data will be stored. 382 * @param usecs Timeout in microseconds. Zero denotes no timeout. 383 * 384 * @return If no timeout was specified, then a hash of the 385 * incoming call is returned. If a timeout is specified, 386 * then a hash of the incoming call is returned unless 387 * the timeout expires prior to receiving a message. In 388 * that case zero is returned. 389 * 342 390 */ 343 391 ipc_callid_t async_get_call_timeout(ipc_call_t *call, suseconds_t usecs) 344 392 { 345 msg_t *msg;346 ipc_callid_t callid;347 connection_t *conn;348 349 393 assert(FIBRIL_connection); 350 /* GCC 4.1.0 coughs on FIBRIL_connection-> dereference, 394 395 /* Why doing this? 396 * GCC 4.1.0 coughs on FIBRIL_connection-> dereference. 351 397 * GCC 4.1.1 happilly puts the rdhwr instruction in delay slot. 352 * I would never expect to find so many errors in 353 * a compiler *($&$(*&$398 * I would never expect to find so many errors in 399 * a compiler. 354 400 */ 355 conn = FIBRIL_connection;356 401 connection_t *conn = FIBRIL_connection; 402 357 403 futex_down(&async_futex); 358 404 359 405 if (usecs) { 360 406 gettimeofday(&conn->wdata.expires, NULL); 361 407 tv_add(&conn->wdata.expires, usecs); 362 } else {363 conn->wdata.inlist = 0;364 }408 } else 409 conn->wdata.inlist = false; 410 365 411 /* If nothing in queue, wait until something arrives */ 366 412 while (list_empty(&conn->msg_queue)) { 367 413 if (usecs) 368 414 insert_timeout(&conn->wdata); 369 370 conn->wdata.active = 0; 415 416 conn->wdata.active = false; 417 371 418 /* 372 419 * Note: the current fibril will be rescheduled either due to a … … 376 423 */ 377 424 fibril_switch(FIBRIL_TO_MANAGER); 425 378 426 /* 379 * Futex is up after getting back from async_manager get it380 * again.427 * Futex is up after getting back from async_manager. 428 * Get it again. 381 429 */ 382 430 futex_down(&async_futex); 383 if ( usecs && conn->wdata.timedout &&384 list_empty(&conn->msg_queue)) {431 if ((usecs) && (conn->wdata.timedout) 432 && (list_empty(&conn->msg_queue))) { 385 433 /* If we timed out -> exit */ 386 434 futex_up(&async_futex); … … 389 437 } 390 438 391 msg = list_get_instance(conn->msg_queue.next, msg_t, link);439 msg_t *msg = list_get_instance(conn->msg_queue.next, msg_t, link); 392 440 list_remove(&msg->link); 393 callid = msg->callid; 441 442 ipc_callid_t callid = msg->callid; 394 443 *call = msg->call; 395 444 free(msg); … … 403 452 * This function is defined as a weak symbol - to be redefined in user code. 404 453 * 405 * @param callid Hash of the incoming call. 406 * @param call Data of the incoming call. 454 * @param callid Hash of the incoming call. 455 * @param call Data of the incoming call. 456 * 407 457 */ 408 458 static void default_client_connection(ipc_callid_t callid, ipc_call_t *call) … … 413 463 /** Default fibril function that gets called to handle interrupt notifications. 414 464 * 415 * @param callid Hash of the incoming call. 416 * @param call Data of the incoming call. 465 * This function is defined as a weak symbol - to be redefined in user code. 466 * 467 * @param callid Hash of the incoming call. 468 * @param call Data of the incoming call. 469 * 417 470 */ 418 471 static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call) … … 425 478 * created. It calls client_connection() and does the final cleanup. 426 479 * 427 * @param arg 428 * 429 * @return 430 * /431 static int connection_fibril(void *arg) 432 { 433 unsigned long key; 434 msg_t *msg;435 int close_answered = 0;436 437 /* Setup fibril-local connection pointer*/480 * @param arg Connection structure pointer. 481 * 482 * @return Always zero. 483 * 484 */ 485 static int connection_fibril(void *arg) 486 { 487 /* 488 * Setup fibril-local connection pointer and call client_connection(). 489 * 490 */ 438 491 FIBRIL_connection = (connection_t *) arg; 439 492 FIBRIL_connection->cfibril(FIBRIL_connection->callid, … … 442 495 /* Remove myself from the connection hash table */ 443 496 futex_down(&async_futex); 444 key = FIBRIL_connection->in_phone_hash;497 unsigned long key = FIBRIL_connection->in_phone_hash; 445 498 hash_table_remove(&conn_hash_table, &key, 1); 446 499 futex_up(&async_futex); … … 448 501 /* Answer all remaining messages with EHANGUP */ 449 502 while (!list_empty(&FIBRIL_connection->msg_queue)) { 450 msg = list_get_instance(FIBRIL_connection->msg_queue.next, 451 msg_t, link); 503 msg_t *msg 504 = list_get_instance(FIBRIL_connection->msg_queue.next, msg_t, link); 505 452 506 list_remove(&msg->link); 453 if (msg->callid == FIBRIL_connection->close_callid)454 close_answered = 1;455 507 ipc_answer_0(msg->callid, EHANGUP); 456 508 free(msg); 457 509 } 510 458 511 if (FIBRIL_connection->close_callid) 459 512 ipc_answer_0(FIBRIL_connection->close_callid, EOK); … … 464 517 /** Create a new fibril for a new connection. 465 518 * 466 * Create s new fibril for connection, fillsin connection structures and inserts519 * Create new fibril for connection, fill in connection structures and inserts 467 520 * it into the hash table, so that later we can easily do routing of messages to 468 521 * particular fibrils. 469 522 * 470 * @param in_phone_hash Identification of the incoming connection. 471 * @param callid Hash of the opening IPC_M_CONNECT_ME_TO call. 472 * If callid is zero, the connection was opened by 473 * accepting the IPC_M_CONNECT_TO_ME call and this function 474 * is called directly by the server. 475 * @param call Call data of the opening call. 476 * @param cfibril Fibril function that should be called upon opening the 477 * connection. 478 * 479 * @return New fibril id or NULL on failure. 523 * @param in_phone_hash Identification of the incoming connection. 524 * @param callid Hash of the opening IPC_M_CONNECT_ME_TO call. 525 * If callid is zero, the connection was opened by 526 * accepting the IPC_M_CONNECT_TO_ME call and this function 527 * is called directly by the server. 528 * @param call Call data of the opening call. 529 * @param cfibril Fibril function that should be called upon opening the 530 * connection. 531 * 532 * @return New fibril id or NULL on failure. 533 * 480 534 */ 481 535 fid_t async_new_connection(ipcarg_t in_phone_hash, ipc_callid_t callid, 482 536 ipc_call_t *call, void (*cfibril)(ipc_callid_t, ipc_call_t *)) 483 537 { 484 connection_t *conn; 485 unsigned long key; 486 487 conn = malloc(sizeof(*conn)); 538 connection_t *conn = malloc(sizeof(*conn)); 488 539 if (!conn) { 489 540 if (callid) … … 491 542 return NULL; 492 543 } 544 493 545 conn->in_phone_hash = in_phone_hash; 494 546 list_initialize(&conn->msg_queue); 495 547 conn->callid = callid; 496 conn->close_callid = 0; 548 conn->close_callid = false; 549 497 550 if (call) 498 551 conn->call = *call; 499 conn->wdata.active = 1; /* We will activate the fibril ASAP */ 552 553 /* We will activate the fibril ASAP */ 554 conn->wdata.active = true; 500 555 conn->cfibril = cfibril; 501 502 556 conn->wdata.fid = fibril_create(connection_fibril, conn); 557 503 558 if (!conn->wdata.fid) { 504 559 free(conn); … … 509 564 510 565 /* Add connection to the connection hash table */ 511 key = conn->in_phone_hash; 566 ipcarg_t key = conn->in_phone_hash; 567 512 568 futex_down(&async_futex); 513 569 hash_table_insert(&conn_hash_table, &key, &conn->link); … … 524 580 * Otherwise the call is routed to its connection fibril. 525 581 * 526 * @param callid 527 * @param call 582 * @param callid Hash of the incoming call. 583 * @param call Data of the incoming call. 528 584 * 529 585 */ … … 532 588 /* Unrouted call - do some default behaviour */ 533 589 if ((callid & IPC_CALLID_NOTIFICATION)) { 534 _in_interrupt_handler = 1; 535 (*interrupt_received)(callid, call); 536 _in_interrupt_handler = 0; 590 process_notification(callid, call); 537 591 return; 538 592 } … … 558 612 { 559 613 struct timeval tv; 560 awaiter_t *waiter;561 link_t *cur;562 563 614 gettimeofday(&tv, NULL); 615 564 616 futex_down(&async_futex); 565 566 cur = timeout_list.next;617 618 link_t *cur = timeout_list.next; 567 619 while (cur != &timeout_list) { 568 waiter = list_get_instance(cur, awaiter_t, link); 620 awaiter_t *waiter = list_get_instance(cur, awaiter_t, link); 621 569 622 if (tv_gt(&waiter->expires, &tv)) 570 623 break; 624 571 625 cur = cur->next; 626 572 627 list_remove(&waiter->link); 573 waiter->inlist = 0; 574 waiter->timedout = 1; 628 waiter->inlist = false; 629 waiter->timedout = true; 630 575 631 /* 576 577 632 * Redundant condition? 633 * The fibril should not be active when it gets here. 578 634 */ 579 635 if (!waiter->active) { 580 waiter->active = 1;636 waiter->active = true; 581 637 fibril_add_ready(waiter->fid); 582 638 } 583 639 } 584 640 585 641 futex_up(&async_futex); 586 642 } … … 588 644 /** Endless loop dispatching incoming calls and answers. 589 645 * 590 * @return Never returns. 646 * @return Never returns. 647 * 591 648 */ 592 649 static int async_manager_worker(void) 593 650 { 594 ipc_call_t call; 595 ipc_callid_t callid; 596 int timeout; 597 awaiter_t *waiter; 598 struct timeval tv; 599 600 while (1) { 651 while (true) { 601 652 if (fibril_switch(FIBRIL_FROM_MANAGER)) { 602 653 futex_up(&async_futex); … … 607 658 continue; 608 659 } 660 609 661 futex_down(&async_futex); 662 663 suseconds_t timeout; 610 664 if (!list_empty(&timeout_list)) { 611 waiter = list_get_instance(timeout_list.next, awaiter_t, 612 link); 665 awaiter_t *waiter 666 = list_get_instance(timeout_list.next, awaiter_t, link); 667 668 struct timeval tv; 613 669 gettimeofday(&tv, NULL); 670 614 671 if (tv_gteq(&tv, &waiter->expires)) { 615 672 futex_up(&async_futex); … … 620 677 } else 621 678 timeout = SYNCH_NO_TIMEOUT; 679 622 680 futex_up(&async_futex); 623 624 callid = ipc_wait_cycle(&call, timeout, SYNCH_FLAGS_NONE); 625 681 682 ipc_call_t call; 683 ipc_callid_t callid 684 = ipc_wait_cycle(&call, timeout, SYNCH_FLAGS_NONE); 685 626 686 if (!callid) { 627 687 handle_expired_timeouts(); 628 688 continue; 629 689 } 630 631 if (callid & IPC_CALLID_ANSWERED) {690 691 if (callid & IPC_CALLID_ANSWERED) 632 692 continue; 633 } 634 693 635 694 handle_call(callid, &call); 636 695 } … … 640 699 641 700 /** Function to start async_manager as a standalone fibril. 642 * 701 * 643 702 * When more kernel threads are used, one async manager should exist per thread. 644 703 * 645 * @param arg 646 * 647 * @return Never returns.704 * @param arg Unused. 705 * @return Never returns. 706 * 648 707 */ 649 708 static int async_manager_fibril(void *arg) 650 709 { 651 710 futex_up(&async_futex); 711 652 712 /* 653 713 * async_futex is always locked when entering manager … … 661 721 void async_create_manager(void) 662 722 { 663 fid_t fid; 664 665 fid = fibril_create(async_manager_fibril, NULL); 723 fid_t fid = fibril_create(async_manager_fibril, NULL); 666 724 fibril_add_manager(fid); 667 725 } … … 675 733 /** Initialize the async framework. 676 734 * 677 * @return 735 * @return Zero on success or an error code. 678 736 */ 679 737 int _async_init(void) … … 695 753 * Notify the fibril which is waiting for this message that it has arrived. 696 754 * 697 * @param private Pointer to the asynchronous message record. 698 * @param retval Value returned in the answer. 699 * @param data Call data of the answer. 700 */ 701 static void reply_received(void *private, int retval, ipc_call_t *data) 702 { 703 amsg_t *msg = (amsg_t *) private; 704 755 * @param arg Pointer to the asynchronous message record. 756 * @param retval Value returned in the answer. 757 * @param data Call data of the answer. 758 */ 759 static void reply_received(void *arg, int retval, ipc_call_t *data) 760 { 761 amsg_t *msg = (amsg_t *) arg; 705 762 msg->retval = retval; 706 763 707 764 futex_down(&async_futex); 765 708 766 /* Copy data after futex_down, just in case the call was detached */ 709 767 if (msg->dataptr) 710 *msg->dataptr = *data; 711 768 *msg->dataptr = *data; 769 712 770 write_barrier(); 771 713 772 /* Remove message from timeout list */ 714 773 if (msg->wdata.inlist) 715 774 list_remove(&msg->wdata.link); 716 msg->done = 1; 775 776 msg->done = true; 717 777 if (!msg->wdata.active) { 718 msg->wdata.active = 1;778 msg->wdata.active = true; 719 779 fibril_add_ready(msg->wdata.fid); 720 780 } 781 721 782 futex_up(&async_futex); 722 783 } … … 727 788 * completion. 728 789 * 729 * @param phoneid Handle of the phone that will be used for the send. 730 * @param method Service-defined method. 731 * @param arg1 Service-defined payload argument. 732 * @param arg2 Service-defined payload argument. 733 * @param arg3 Service-defined payload argument. 734 * @param arg4 Service-defined payload argument. 735 * @param dataptr If non-NULL, storage where the reply data will be 736 * stored. 737 * 738 * @return Hash of the sent message. 790 * @param phoneid Handle of the phone that will be used for the send. 791 * @param method Service-defined method. 792 * @param arg1 Service-defined payload argument. 793 * @param arg2 Service-defined payload argument. 794 * @param arg3 Service-defined payload argument. 795 * @param arg4 Service-defined payload argument. 796 * @param dataptr If non-NULL, storage where the reply data will be 797 * stored. 798 * 799 * @return Hash of the sent message or 0 on error. 800 * 739 801 */ 740 802 aid_t async_send_fast(int phoneid, ipcarg_t method, ipcarg_t arg1, 741 803 ipcarg_t arg2, ipcarg_t arg3, ipcarg_t arg4, ipc_call_t *dataptr) 742 804 { 743 amsg_t *msg; 744 745 msg = malloc(sizeof(*msg)); 746 msg->done = 0; 805 amsg_t *msg = malloc(sizeof(*msg)); 806 807 if (!msg) 808 return 0; 809 810 msg->done = false; 747 811 msg->dataptr = dataptr; 748 812 749 813 /* We may sleep in the next method, but it will use its own mechanism */ 750 msg->wdata.active = 1;751 814 msg->wdata.active = true; 815 752 816 ipc_call_async_4(phoneid, method, arg1, arg2, arg3, arg4, msg, 753 reply_received, !_in_interrupt_handler);817 reply_received, true); 754 818 755 819 return (aid_t) msg; … … 761 825 * completion. 762 826 * 763 * @param phoneid Handle of the phone that will be used for the send. 764 * @param method Service-defined method. 765 * @param arg1 Service-defined payload argument. 766 * @param arg2 Service-defined payload argument. 767 * @param arg3 Service-defined payload argument. 768 * @param arg4 Service-defined payload argument. 769 * @param arg5 Service-defined payload argument. 770 * @param dataptr If non-NULL, storage where the reply data will be 771 * stored. 772 * 773 * @return Hash of the sent message. 827 * @param phoneid Handle of the phone that will be used for the send. 828 * @param method Service-defined method. 829 * @param arg1 Service-defined payload argument. 830 * @param arg2 Service-defined payload argument. 831 * @param arg3 Service-defined payload argument. 832 * @param arg4 Service-defined payload argument. 833 * @param arg5 Service-defined payload argument. 834 * @param dataptr If non-NULL, storage where the reply data will be 835 * stored. 836 * 837 * @return Hash of the sent message or 0 on error. 838 * 774 839 */ 775 840 aid_t async_send_slow(int phoneid, ipcarg_t method, ipcarg_t arg1, … … 777 842 ipc_call_t *dataptr) 778 843 { 779 amsg_t *msg; 780 781 msg = malloc(sizeof(*msg)); 782 msg->done = 0; 844 amsg_t *msg = malloc(sizeof(*msg)); 845 846 if (!msg) 847 return 0; 848 849 msg->done = false; 783 850 msg->dataptr = dataptr; 784 851 785 852 /* We may sleep in next method, but it will use its own mechanism */ 786 msg->wdata.active = 1;853 msg->wdata.active = true; 787 854 788 855 ipc_call_async_5(phoneid, method, arg1, arg2, arg3, arg4, arg5, msg, 789 reply_received, !_in_interrupt_handler);856 reply_received, true); 790 857 791 858 return (aid_t) msg; … … 794 861 /** Wait for a message sent by the async framework. 795 862 * 796 * @param amsgid Hash of the message to wait for. 797 * @param retval Pointer to storage where the retval of the answer will 798 * be stored. 863 * @param amsgid Hash of the message to wait for. 864 * @param retval Pointer to storage where the retval of the answer will 865 * be stored. 866 * 799 867 */ 800 868 void async_wait_for(aid_t amsgid, ipcarg_t *retval) 801 869 { 802 870 amsg_t *msg = (amsg_t *) amsgid; 803 871 804 872 futex_down(&async_futex); 805 873 if (msg->done) { … … 807 875 goto done; 808 876 } 809 877 810 878 msg->wdata.fid = fibril_get_id(); 811 msg->wdata.active = 0; 812 msg->wdata.inlist = 0; 879 msg->wdata.active = false; 880 msg->wdata.inlist = false; 881 813 882 /* Leave the async_futex locked when entering this function */ 814 883 fibril_switch(FIBRIL_TO_MANAGER); 815 /* futex is up automatically after fibril_switch...*/ 884 885 /* Futex is up automatically after fibril_switch */ 886 816 887 done: 817 888 if (retval) 818 889 *retval = msg->retval; 890 819 891 free(msg); 820 892 } … … 822 894 /** Wait for a message sent by the async framework, timeout variant. 823 895 * 824 * @param amsgid Hash of the message to wait for. 825 * @param retval Pointer to storage where the retval of the answer will 826 * be stored. 827 * @param timeout Timeout in microseconds. 828 * 829 * @return Zero on success, ETIMEOUT if the timeout has expired. 896 * @param amsgid Hash of the message to wait for. 897 * @param retval Pointer to storage where the retval of the answer will 898 * be stored. 899 * @param timeout Timeout in microseconds. 900 * 901 * @return Zero on success, ETIMEOUT if the timeout has expired. 902 * 830 903 */ 831 904 int async_wait_timeout(aid_t amsgid, ipcarg_t *retval, suseconds_t timeout) 832 905 { 833 906 amsg_t *msg = (amsg_t *) amsgid; 834 907 835 908 /* TODO: Let it go through the event read at least once */ 836 909 if (timeout < 0) 837 910 return ETIMEOUT; 838 911 839 912 futex_down(&async_futex); 840 913 if (msg->done) { … … 842 915 goto done; 843 916 } 844 917 845 918 gettimeofday(&msg->wdata.expires, NULL); 846 919 tv_add(&msg->wdata.expires, timeout); 847 920 848 921 msg->wdata.fid = fibril_get_id(); 849 msg->wdata.active = 0;922 msg->wdata.active = false; 850 923 insert_timeout(&msg->wdata); 851 924 852 925 /* Leave the async_futex locked when entering this function */ 853 926 fibril_switch(FIBRIL_TO_MANAGER); 854 /* futex is up automatically after fibril_switch...*/ 855 927 928 /* Futex is up automatically after fibril_switch */ 929 856 930 if (!msg->done) 857 931 return ETIMEOUT; 858 932 859 933 done: 860 934 if (retval) 861 935 *retval = msg->retval; 936 862 937 free(msg); 863 938 864 939 return 0; 865 940 } … … 869 944 * The current fibril is suspended but the thread continues to execute. 870 945 * 871 * @param timeout Duration of the wait in microseconds. 946 * @param timeout Duration of the wait in microseconds. 947 * 872 948 */ 873 949 void async_usleep(suseconds_t timeout) 874 950 { 875 amsg_t *msg; 876 877 msg = malloc(sizeof(*msg)); 951 amsg_t *msg = malloc(sizeof(*msg)); 952 878 953 if (!msg) 879 954 return; 880 955 881 956 msg->wdata.fid = fibril_get_id(); 882 msg->wdata.active = 0;957 msg->wdata.active = false; 883 958 884 959 gettimeofday(&msg->wdata.expires, NULL); … … 886 961 887 962 futex_down(&async_futex); 963 888 964 insert_timeout(&msg->wdata); 965 889 966 /* Leave the async_futex locked when entering this function */ 890 967 fibril_switch(FIBRIL_TO_MANAGER); 891 /* futex is up automatically after fibril_switch()...*/ 968 969 /* Futex is up automatically after fibril_switch() */ 970 892 971 free(msg); 893 972 } … … 895 974 /** Setter for client_connection function pointer. 896 975 * 897 * @param conn Function that will implement a new connection fibril. 976 * @param conn Function that will implement a new connection fibril. 977 * 898 978 */ 899 979 void async_set_client_connection(async_client_conn_t conn) … … 904 984 /** Setter for interrupt_received function pointer. 905 985 * 906 * @param connFunction that will implement a new interrupt907 * 908 */ 909 void async_set_interrupt_received(async_client_conn_t conn)910 { 911 interrupt_received = conn;986 * @param intr Function that will implement a new interrupt 987 * notification fibril. 988 */ 989 void async_set_interrupt_received(async_client_conn_t intr) 990 { 991 interrupt_received = intr; 912 992 } 913 993 … … 919 999 * transferring more arguments, see the slower async_req_slow(). 920 1000 * 921 * @param phoneid Hash of the phone through which to make the call. 922 * @param method Method of the call. 923 * @param arg1 Service-defined payload argument. 924 * @param arg2 Service-defined payload argument. 925 * @param arg3 Service-defined payload argument. 926 * @param arg4 Service-defined payload argument. 927 * @param r1 If non-NULL, storage for the 1st reply argument. 928 * @param r2 If non-NULL, storage for the 2nd reply argument. 929 * @param r3 If non-NULL, storage for the 3rd reply argument. 930 * @param r4 If non-NULL, storage for the 4th reply argument. 931 * @param r5 If non-NULL, storage for the 5th reply argument. 932 * @return Return code of the reply or a negative error code. 1001 * @param phoneid Hash of the phone through which to make the call. 1002 * @param method Method of the call. 1003 * @param arg1 Service-defined payload argument. 1004 * @param arg2 Service-defined payload argument. 1005 * @param arg3 Service-defined payload argument. 1006 * @param arg4 Service-defined payload argument. 1007 * @param r1 If non-NULL, storage for the 1st reply argument. 1008 * @param r2 If non-NULL, storage for the 2nd reply argument. 1009 * @param r3 If non-NULL, storage for the 3rd reply argument. 1010 * @param r4 If non-NULL, storage for the 4th reply argument. 1011 * @param r5 If non-NULL, storage for the 5th reply argument. 1012 * 1013 * @return Return code of the reply or a negative error code. 1014 * 933 1015 */ 934 1016 ipcarg_t async_req_fast(int phoneid, ipcarg_t method, ipcarg_t arg1, … … 937 1019 { 938 1020 ipc_call_t result; 939 ipcarg_t rc;940 941 1021 aid_t eid = async_send_4(phoneid, method, arg1, arg2, arg3, arg4, 942 1022 &result); 1023 1024 ipcarg_t rc; 943 1025 async_wait_for(eid, &rc); 944 if (r1) 1026 1027 if (r1) 945 1028 *r1 = IPC_GET_ARG1(result); 1029 946 1030 if (r2) 947 1031 *r2 = IPC_GET_ARG2(result); 1032 948 1033 if (r3) 949 1034 *r3 = IPC_GET_ARG3(result); 1035 950 1036 if (r4) 951 1037 *r4 = IPC_GET_ARG4(result); 1038 952 1039 if (r5) 953 1040 *r5 = IPC_GET_ARG5(result); 1041 954 1042 return rc; 955 1043 } … … 959 1047 * Send message asynchronously and return only after the reply arrives. 960 1048 * 961 * @param phoneid Hash of the phone through which to make the call. 962 * @param method Method of the call. 963 * @param arg1 Service-defined payload argument. 964 * @param arg2 Service-defined payload argument. 965 * @param arg3 Service-defined payload argument. 966 * @param arg4 Service-defined payload argument. 967 * @param arg5 Service-defined payload argument. 968 * @param r1 If non-NULL, storage for the 1st reply argument. 969 * @param r2 If non-NULL, storage for the 2nd reply argument. 970 * @param r3 If non-NULL, storage for the 3rd reply argument. 971 * @param r4 If non-NULL, storage for the 4th reply argument. 972 * @param r5 If non-NULL, storage for the 5th reply argument. 973 * @return Return code of the reply or a negative error code. 1049 * @param phoneid Hash of the phone through which to make the call. 1050 * @param method Method of the call. 1051 * @param arg1 Service-defined payload argument. 1052 * @param arg2 Service-defined payload argument. 1053 * @param arg3 Service-defined payload argument. 1054 * @param arg4 Service-defined payload argument. 1055 * @param arg5 Service-defined payload argument. 1056 * @param r1 If non-NULL, storage for the 1st reply argument. 1057 * @param r2 If non-NULL, storage for the 2nd reply argument. 1058 * @param r3 If non-NULL, storage for the 3rd reply argument. 1059 * @param r4 If non-NULL, storage for the 4th reply argument. 1060 * @param r5 If non-NULL, storage for the 5th reply argument. 1061 * 1062 * @return Return code of the reply or a negative error code. 1063 * 974 1064 */ 975 1065 ipcarg_t async_req_slow(int phoneid, ipcarg_t method, ipcarg_t arg1, … … 978 1068 { 979 1069 ipc_call_t result; 980 ipcarg_t rc;981 982 1070 aid_t eid = async_send_5(phoneid, method, arg1, arg2, arg3, arg4, arg5, 983 1071 &result); 1072 1073 ipcarg_t rc; 984 1074 async_wait_for(eid, &rc); 985 if (r1) 1075 1076 if (r1) 986 1077 *r1 = IPC_GET_ARG1(result); 1078 987 1079 if (r2) 988 1080 *r2 = IPC_GET_ARG2(result); 1081 989 1082 if (r3) 990 1083 *r3 = IPC_GET_ARG3(result); 1084 991 1085 if (r4) 992 1086 *r4 = IPC_GET_ARG4(result); 1087 993 1088 if (r5) 994 1089 *r5 = IPC_GET_ARG5(result); 1090 995 1091 return rc; 996 1092 }
Note:
See TracChangeset
for help on using the changeset viewer.