Rev 1490 | Rev 1503 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1490 | Rev 1500 | ||
---|---|---|---|
Line 96... | Line 96... | ||
96 | atomic_t async_futex = FUTEX_INITIALIZER; |
96 | atomic_t async_futex = FUTEX_INITIALIZER; |
97 | static hash_table_t conn_hash_table; |
97 | static hash_table_t conn_hash_table; |
98 | static LIST_INITIALIZE(timeout_list); |
98 | static LIST_INITIALIZE(timeout_list); |
99 | 99 | ||
100 | typedef struct { |
100 | typedef struct { |
- | 101 | struct timeval expires; /**< Expiration time for waiting thread */ |
|
- | 102 | int inlist; /**< If true, this struct is in timeout list */ |
|
- | 103 | link_t link; |
|
- | 104 | ||
101 | pstid_t ptid; /**< Thread waiting for this message */ |
105 | pstid_t ptid; /**< Thread waiting for this message */ |
102 | int active; /**< If this thread is currently active */ |
106 | int active; /**< If this thread is currently active */ |
- | 107 | int timedout; /**< If true, we timed out */ |
|
- | 108 | } awaiter_t; |
|
- | 109 | ||
- | 110 | typedef struct { |
|
- | 111 | awaiter_t wdata; |
|
- | 112 | ||
103 | int done; /**< If reply was received */ |
113 | int done; /**< If reply was received */ |
104 | ipc_call_t *dataptr; /**< Pointer where the answer data |
114 | ipc_call_t *dataptr; /**< Pointer where the answer data |
105 | * should be stored */ |
115 | * is stored */ |
106 | struct timeval expires; /**< Expiration time for waiting thread */ |
- | |
107 | int has_timeout; /**< If true, this struct is in timeout list */ |
- | |
108 | link_t link; |
- | |
109 | - | ||
110 | ipcarg_t retval; |
116 | ipcarg_t retval; |
111 | } amsg_t; |
117 | } amsg_t; |
112 | 118 | ||
113 | typedef struct { |
119 | typedef struct { |
114 | link_t link; |
120 | link_t link; |
115 | ipc_callid_t callid; |
121 | ipc_callid_t callid; |
116 | ipc_call_t call; |
122 | ipc_call_t call; |
117 | } msg_t; |
123 | } msg_t; |
118 | 124 | ||
119 | typedef struct { |
125 | typedef struct { |
120 | link_t link; |
126 | awaiter_t wdata; |
- | 127 | ||
- | 128 | link_t link; /**< Hash table link */ |
|
121 | ipcarg_t in_phone_hash; /**< Incoming phone hash. */ |
129 | ipcarg_t in_phone_hash; /**< Incoming phone hash. */ |
122 | link_t msg_queue; /**< Messages that should be delivered to this thread */ |
130 | link_t msg_queue; /**< Messages that should be delivered to this thread */ |
123 | pstid_t ptid; /**< Thread associated with this connection */ |
- | |
124 | int active; /**< If this thread is currently active */ |
- | |
125 | /* Structures for connection opening packet */ |
131 | /* Structures for connection opening packet */ |
126 | ipc_callid_t callid; |
132 | ipc_callid_t callid; |
127 | ipc_call_t call; |
133 | ipc_call_t call; |
128 | void (*cthread)(ipc_callid_t,ipc_call_t *); |
134 | void (*cthread)(ipc_callid_t,ipc_call_t *); |
129 | } connection_t; |
135 | } connection_t; |
Line 206... | Line 212... | ||
206 | .hash = conn_hash, |
212 | .hash = conn_hash, |
207 | .compare = conn_compare, |
213 | .compare = conn_compare, |
208 | .remove_callback = conn_remove |
214 | .remove_callback = conn_remove |
209 | }; |
215 | }; |
210 | 216 | ||
- | 217 | /** Insert sort timeout msg into timeouts list |
|
- | 218 | * |
|
- | 219 | * Assume async_futex is held |
|
- | 220 | */ |
|
- | 221 | static void insert_timeout(awaiter_t *wd) |
|
- | 222 | { |
|
- | 223 | link_t *tmp; |
|
- | 224 | awaiter_t *cur; |
|
- | 225 | ||
- | 226 | wd->timedout = 0; |
|
- | 227 | ||
- | 228 | tmp = timeout_list.next; |
|
- | 229 | while (tmp != &timeout_list) { |
|
- | 230 | cur = list_get_instance(tmp, awaiter_t, link); |
|
- | 231 | if (tv_gteq(&cur->expires, &wd->expires)) |
|
- | 232 | break; |
|
- | 233 | tmp = tmp->next; |
|
- | 234 | } |
|
- | 235 | list_append(&wd->link, tmp); |
|
- | 236 | } |
|
- | 237 | ||
211 | /*************************************************/ |
238 | /*************************************************/ |
212 | 239 | ||
213 | /** Try to route a call to an appropriate connection thread |
240 | /** Try to route a call to an appropriate connection thread |
214 | * |
241 | * |
215 | */ |
242 | */ |
Line 233... | Line 260... | ||
233 | msg = malloc(sizeof(*msg)); |
260 | msg = malloc(sizeof(*msg)); |
234 | msg->callid = callid; |
261 | msg->callid = callid; |
235 | msg->call = *call; |
262 | msg->call = *call; |
236 | list_append(&msg->link, &conn->msg_queue); |
263 | list_append(&msg->link, &conn->msg_queue); |
237 | 264 | ||
- | 265 | /* If the call is waiting for event, run it */ |
|
238 | if (!conn->active) { |
266 | if (!conn->wdata.active) { |
- | 267 | /* If in timeout list, remove it */ |
|
- | 268 | if (conn->wdata.inlist) { |
|
- | 269 | conn->wdata.inlist = 0; |
|
- | 270 | list_remove(&conn->wdata.link); |
|
- | 271 | } |
|
239 | conn->active = 1; |
272 | conn->wdata.active = 1; |
240 | psthread_add_ready(conn->ptid); |
273 | psthread_add_ready(conn->wdata.ptid); |
241 | } |
274 | } |
242 | 275 | ||
243 | futex_up(&async_futex); |
276 | futex_up(&async_futex); |
244 | 277 | ||
245 | return 1; |
278 | return 1; |
246 | } |
279 | } |
247 | 280 | ||
248 | /** Return new incoming message for current(thread-local) connection */ |
281 | /** Return new incoming message for current(thread-local) connection */ |
249 | ipc_callid_t async_get_call(ipc_call_t *call) |
282 | ipc_callid_t async_get_call_timeout(ipc_call_t *call, suseconds_t usecs) |
250 | { |
283 | { |
251 | msg_t *msg; |
284 | msg_t *msg; |
252 | ipc_callid_t callid; |
285 | ipc_callid_t callid; |
253 | 286 | ||
254 | assert(PS_connection); |
287 | assert(PS_connection); |
255 | 288 | ||
256 | futex_down(&async_futex); |
289 | futex_down(&async_futex); |
257 | 290 | ||
- | 291 | if (usecs) { |
|
- | 292 | gettimeofday(&PS_connection->wdata.expires, NULL); |
|
- | 293 | tv_add(&PS_connection->wdata.expires, usecs); |
|
- | 294 | } else { |
|
- | 295 | PS_connection->wdata.inlist = 0; |
|
- | 296 | } |
|
258 | /* If nothing in queue, wait until something appears */ |
297 | /* If nothing in queue, wait until something appears */ |
259 | if (list_empty(&PS_connection->msg_queue)) { |
298 | while (list_empty(&PS_connection->msg_queue)) { |
- | 299 | if (usecs) { |
|
- | 300 | PS_connection->wdata.inlist = 1; |
|
- | 301 | insert_timeout(&PS_connection->wdata); |
|
- | 302 | } |
|
260 | PS_connection->active = 0; |
303 | PS_connection->wdata.active = 0; |
261 | psthread_schedule_next_adv(PS_TO_MANAGER); |
304 | psthread_schedule_next_adv(PS_TO_MANAGER); |
- | 305 | /* Futex is up after getting back from async_manager |
|
- | 306 | * get it again */ |
|
- | 307 | futex_down(&async_futex); |
|
- | 308 | if (usecs && PS_connection->wdata.timedout && \ |
|
- | 309 | list_empty(&PS_connection->msg_queue)) { |
|
- | 310 | /* If we timed out-> exit */ |
|
- | 311 | futex_up(&async_futex); |
|
- | 312 | return 0; |
|
- | 313 | } |
|
262 | } |
314 | } |
263 | 315 | ||
264 | msg = list_get_instance(PS_connection->msg_queue.next, msg_t, link); |
316 | msg = list_get_instance(PS_connection->msg_queue.next, msg_t, link); |
265 | list_remove(&msg->link); |
317 | list_remove(&msg->link); |
266 | callid = msg->callid; |
318 | callid = msg->callid; |
Line 348... | Line 400... | ||
348 | ipc_answer_fast(callid, ENOMEM, 0, 0); |
400 | ipc_answer_fast(callid, ENOMEM, 0, 0); |
349 | return NULL; |
401 | return NULL; |
350 | } |
402 | } |
351 | conn->in_phone_hash = in_phone_hash; |
403 | conn->in_phone_hash = in_phone_hash; |
352 | list_initialize(&conn->msg_queue); |
404 | list_initialize(&conn->msg_queue); |
353 | conn->ptid = psthread_create(connection_thread, conn); |
- | |
354 | conn->callid = callid; |
405 | conn->callid = callid; |
355 | if (call) |
406 | if (call) |
356 | conn->call = *call; |
407 | conn->call = *call; |
357 | conn->active = 1; /* We will activate it asap */ |
408 | conn->wdata.active = 1; /* We will activate it asap */ |
358 | conn->cthread = cthread; |
409 | conn->cthread = cthread; |
- | 410 | ||
359 | list_initialize(&conn->link); |
411 | conn->wdata.ptid = psthread_create(connection_thread, conn); |
360 | if (!conn->ptid) { |
412 | if (!conn->wdata.ptid) { |
361 | free(conn); |
413 | free(conn); |
362 | ipc_answer_fast(callid, ENOMEM, 0, 0); |
414 | ipc_answer_fast(callid, ENOMEM, 0, 0); |
363 | return NULL; |
415 | return NULL; |
364 | } |
416 | } |
- | 417 | /* Add connection to hash table */ |
|
365 | key = conn->in_phone_hash; |
418 | key = conn->in_phone_hash; |
366 | futex_down(&async_futex); |
419 | futex_down(&async_futex); |
367 | /* Add connection to hash table */ |
- | |
368 | hash_table_insert(&conn_hash_table, &key, &conn->link); |
420 | hash_table_insert(&conn_hash_table, &key, &conn->link); |
369 | futex_up(&async_futex); |
421 | futex_up(&async_futex); |
370 | 422 | ||
371 | psthread_add_ready(conn->ptid); |
423 | psthread_add_ready(conn->wdata.ptid); |
372 | 424 | ||
373 | return conn->ptid; |
425 | return conn->wdata.ptid; |
374 | } |
426 | } |
375 | 427 | ||
376 | /** Handle call that was received */ |
428 | /** Handle call that was received */ |
377 | static void handle_call(ipc_callid_t callid, ipc_call_t *call) |
429 | static void handle_call(ipc_callid_t callid, ipc_call_t *call) |
378 | { |
430 | { |
Line 397... | Line 449... | ||
397 | 449 | ||
398 | /** Fire all timeouts that expired */ |
450 | /** Fire all timeouts that expired */ |
399 | static void handle_expired_timeouts(void) |
451 | static void handle_expired_timeouts(void) |
400 | { |
452 | { |
401 | struct timeval tv; |
453 | struct timeval tv; |
402 | amsg_t *amsg; |
454 | awaiter_t *waiter; |
403 | link_t *cur; |
455 | link_t *cur; |
404 | 456 | ||
405 | gettimeofday(&tv,NULL); |
457 | gettimeofday(&tv,NULL); |
406 | futex_down(&async_futex); |
458 | futex_down(&async_futex); |
407 | 459 | ||
408 | cur = timeout_list.next; |
460 | cur = timeout_list.next; |
409 | while (cur != &timeout_list) { |
461 | while (cur != &timeout_list) { |
410 | amsg = list_get_instance(cur,amsg_t,link); |
462 | waiter = list_get_instance(cur,awaiter_t,link); |
411 | if (tv_gt(&amsg->expires, &tv)) |
463 | if (tv_gt(&waiter->expires, &tv)) |
412 | break; |
464 | break; |
413 | cur = cur->next; |
465 | cur = cur->next; |
414 | list_remove(&amsg->link); |
466 | list_remove(&waiter->link); |
- | 467 | waiter->inlist = 0; |
|
415 | amsg->has_timeout = 0; |
468 | waiter->timedout = 1; |
416 | /* Redundant condition? The thread should not |
469 | /* Redundant condition? The thread should not |
417 | * be active when it gets here. |
470 | * be active when it gets here. |
418 | */ |
471 | */ |
419 | if (!amsg->active) { |
472 | if (!waiter->active) { |
420 | amsg->active = 1; |
473 | waiter->active = 1; |
421 | psthread_add_ready(amsg->ptid); |
474 | psthread_add_ready(waiter->ptid); |
422 | } |
475 | } |
423 | } |
476 | } |
424 | 477 | ||
425 | futex_up(&async_futex); |
478 | futex_up(&async_futex); |
426 | } |
479 | } |
Line 429... | Line 482... | ||
429 | int async_manager(void) |
482 | int async_manager(void) |
430 | { |
483 | { |
431 | ipc_call_t call; |
484 | ipc_call_t call; |
432 | ipc_callid_t callid; |
485 | ipc_callid_t callid; |
433 | int timeout; |
486 | int timeout; |
434 | amsg_t *amsg; |
487 | awaiter_t *waiter; |
435 | struct timeval tv; |
488 | struct timeval tv; |
436 | 489 | ||
437 | while (1) { |
490 | while (1) { |
438 | if (psthread_schedule_next_adv(PS_FROM_MANAGER)) { |
491 | if (psthread_schedule_next_adv(PS_FROM_MANAGER)) { |
439 | futex_up(&async_futex); /* async_futex is always held |
492 | futex_up(&async_futex); /* async_futex is always held |
Line 441... | Line 494... | ||
441 | */ |
494 | */ |
442 | continue; |
495 | continue; |
443 | } |
496 | } |
444 | futex_down(&async_futex); |
497 | futex_down(&async_futex); |
445 | if (!list_empty(&timeout_list)) { |
498 | if (!list_empty(&timeout_list)) { |
446 | amsg = list_get_instance(timeout_list.next,amsg_t,link); |
499 | waiter = list_get_instance(timeout_list.next,awaiter_t,link); |
447 | gettimeofday(&tv,NULL); |
500 | gettimeofday(&tv,NULL); |
448 | if (tv_gteq(&tv, &amsg->expires)) { |
501 | if (tv_gteq(&tv, &waiter->expires)) { |
449 | handle_expired_timeouts(); |
502 | handle_expired_timeouts(); |
450 | continue; |
503 | continue; |
451 | } else |
504 | } else |
452 | timeout = tv_sub(&amsg->expires, &tv); |
505 | timeout = tv_sub(&waiter->expires, &tv); |
453 | } else |
506 | } else |
454 | timeout = SYNCH_NO_TIMEOUT; |
507 | timeout = SYNCH_NO_TIMEOUT; |
455 | futex_up(&async_futex); |
508 | futex_up(&async_futex); |
456 | 509 | ||
457 | callid = ipc_wait_cycle(&call, timeout, SYNCH_BLOCKING); |
510 | callid = ipc_wait_cycle(&call, timeout, SYNCH_BLOCKING); |
Line 525... | Line 578... | ||
525 | if (msg->dataptr) |
578 | if (msg->dataptr) |
526 | *msg->dataptr = *data; |
579 | *msg->dataptr = *data; |
527 | 580 | ||
528 | write_barrier(); |
581 | write_barrier(); |
529 | /* Remove message from timeout list */ |
582 | /* Remove message from timeout list */ |
530 | if (msg->has_timeout) |
583 | if (msg->wdata.inlist) |
531 | list_remove(&msg->link); |
584 | list_remove(&msg->wdata.link); |
532 | msg->done = 1; |
585 | msg->done = 1; |
533 | if (! msg->active) { |
586 | if (! msg->wdata.active) { |
534 | msg->active = 1; |
587 | msg->wdata.active = 1; |
535 | psthread_add_ready(msg->ptid); |
588 | psthread_add_ready(msg->wdata.ptid); |
536 | } |
589 | } |
537 | futex_up(&async_futex); |
590 | futex_up(&async_futex); |
538 | } |
591 | } |
539 | 592 | ||
540 | /** Send message and return id of the sent message |
593 | /** Send message and return id of the sent message |
Line 546... | Line 599... | ||
546 | ipc_call_t *dataptr) |
599 | ipc_call_t *dataptr) |
547 | { |
600 | { |
548 | amsg_t *msg; |
601 | amsg_t *msg; |
549 | 602 | ||
550 | msg = malloc(sizeof(*msg)); |
603 | msg = malloc(sizeof(*msg)); |
551 | msg->active = 1; |
- | |
552 | msg->done = 0; |
604 | msg->done = 0; |
553 | msg->dataptr = dataptr; |
605 | msg->dataptr = dataptr; |
- | 606 | ||
- | 607 | msg->wdata.active = 1; /* We may sleep in next method, but it |
|
- | 608 | * will use it's own mechanism */ |
|
554 | ipc_call_async_2(phoneid,method,arg1,arg2,msg,reply_received); |
609 | ipc_call_async_2(phoneid,method,arg1,arg2,msg,reply_received); |
555 | 610 | ||
556 | return (aid_t) msg; |
611 | return (aid_t) msg; |
557 | } |
612 | } |
558 | 613 | ||
Line 572... | Line 627... | ||
572 | if (msg->done) { |
627 | if (msg->done) { |
573 | futex_up(&async_futex); |
628 | futex_up(&async_futex); |
574 | goto done; |
629 | goto done; |
575 | } |
630 | } |
576 | 631 | ||
577 | msg->ptid = psthread_get_id(); |
632 | msg->wdata.ptid = psthread_get_id(); |
578 | msg->active = 0; |
633 | msg->wdata.active = 0; |
579 | msg->has_timeout = 0; |
634 | msg->wdata.inlist = 0; |
580 | /* Leave locked async_futex when entering this function */ |
635 | /* Leave locked async_futex when entering this function */ |
581 | psthread_schedule_next_adv(PS_TO_MANAGER); |
636 | psthread_schedule_next_adv(PS_TO_MANAGER); |
582 | /* futex is up automatically after psthread_schedule_next...*/ |
637 | /* futex is up automatically after psthread_schedule_next...*/ |
583 | done: |
638 | done: |
584 | if (retval) |
639 | if (retval) |
585 | *retval = msg->retval; |
640 | *retval = msg->retval; |
586 | free(msg); |
641 | free(msg); |
587 | } |
642 | } |
588 | 643 | ||
589 | /** Insert sort timeout msg into timeouts list |
- | |
590 | * |
- | |
591 | * Assume async_futex is held |
- | |
592 | */ |
- | |
593 | static void insert_timeout(amsg_t *msg) |
- | |
594 | { |
- | |
595 | link_t *tmp; |
- | |
596 | amsg_t *cur; |
- | |
597 | - | ||
598 | tmp = timeout_list.next; |
- | |
599 | while (tmp != &timeout_list) { |
- | |
600 | cur = list_get_instance(tmp, amsg_t, link); |
- | |
601 | if (tv_gteq(&cur->expires, &msg->expires)) |
- | |
602 | break; |
- | |
603 | tmp = tmp->next; |
- | |
604 | } |
- | |
605 | list_append(&msg->link, tmp); |
- | |
606 | } |
- | |
607 | - | ||
608 | /** Wait for a message sent by async framework with timeout |
644 | /** Wait for a message sent by async framework with timeout |
609 | * |
645 | * |
610 | * @param amsgid Message ID to wait for |
646 | * @param amsgid Message ID to wait for |
611 | * @param retval Pointer to variable where will be stored retval |
647 | * @param retval Pointer to variable where will be stored retval |
612 | * of the answered message. If NULL, it is ignored. |
648 | * of the answered message. If NULL, it is ignored. |
Line 623... | Line 659... | ||
623 | if (msg->done) { |
659 | if (msg->done) { |
624 | futex_up(&async_futex); |
660 | futex_up(&async_futex); |
625 | goto done; |
661 | goto done; |
626 | } |
662 | } |
627 | 663 | ||
- | 664 | gettimeofday(&msg->wdata.expires, NULL); |
|
- | 665 | tv_add(&msg->wdata.expires, timeout); |
|
- | 666 | ||
628 | msg->ptid = psthread_get_id(); |
667 | msg->wdata.ptid = psthread_get_id(); |
629 | msg->active = 0; |
668 | msg->wdata.active = 0; |
630 | msg->has_timeout = 1; |
669 | msg->wdata.inlist = 1; |
631 | 670 | ||
632 | gettimeofday(&msg->expires, NULL); |
- | |
633 | tv_add(&msg->expires, timeout); |
- | |
634 | insert_timeout(msg); |
671 | insert_timeout(&msg->wdata); |
635 | 672 | ||
636 | /* Leave locked async_futex when entering this function */ |
673 | /* Leave locked async_futex when entering this function */ |
637 | psthread_schedule_next_adv(PS_TO_MANAGER); |
674 | psthread_schedule_next_adv(PS_TO_MANAGER); |
638 | /* futex is up automatically after psthread_schedule_next...*/ |
675 | /* futex is up automatically after psthread_schedule_next...*/ |
639 | 676 | ||
Line 658... | Line 695... | ||
658 | 695 | ||
659 | msg = malloc(sizeof(*msg)); |
696 | msg = malloc(sizeof(*msg)); |
660 | if (!msg) |
697 | if (!msg) |
661 | return; |
698 | return; |
662 | 699 | ||
663 | msg->ptid = psthread_get_id(); |
700 | msg->wdata.ptid = psthread_get_id(); |
664 | msg->active = 0; |
701 | msg->wdata.inlist = 1; |
665 | msg->has_timeout = 1; |
702 | msg->wdata.active = 0; |
666 | 703 | ||
667 | gettimeofday(&msg->expires, NULL); |
704 | gettimeofday(&msg->wdata.expires, NULL); |
668 | tv_add(&msg->expires, timeout); |
705 | tv_add(&msg->wdata.expires, timeout); |
669 | 706 | ||
670 | futex_down(&async_futex); |
707 | futex_down(&async_futex); |
671 | insert_timeout(msg); |
708 | insert_timeout(&msg->wdata); |
672 | /* Leave locked async_futex when entering this function */ |
709 | /* Leave locked async_futex when entering this function */ |
673 | psthread_schedule_next_adv(PS_TO_MANAGER); |
710 | psthread_schedule_next_adv(PS_TO_MANAGER); |
674 | /* futex is up automatically after psthread_schedule_next...*/ |
711 | /* futex is up automatically after psthread_schedule_next...*/ |
675 | free(msg); |
712 | free(msg); |
676 | } |
713 | } |