Changeset 349 for pjproject/trunk/pjlib/src/pj/ioqueue_winnt.c
- Timestamp:
- Mar 22, 2006 11:49:19 AM (18 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjlib/src/pj/ioqueue_winnt.c
r83 r349 100 100 }; 101 101 102 enum { POST_QUIT_LEN = 0xFFFFDEADUL }; 103 102 104 /* 103 105 * Structure for individual socket. … … 113 115 #endif 114 116 pj_ioqueue_callback cb; 117 pj_bool_t has_quit_signal; 115 118 }; 116 119 … … 393 396 } 394 397 395 /*396 * pj_ioqueue_unregister()397 */398 PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key )399 {400 PJ_ASSERT_RETURN(key, PJ_EINVAL);401 402 #if PJ_HAS_TCP403 if (key->connecting) {404 unsigned pos;405 pj_ioqueue_t *ioqueue;406 407 ioqueue = key->ioqueue;408 409 /* Erase from connecting_handles */410 pj_lock_acquire(ioqueue->lock);411 for (pos=0; pos < ioqueue->connecting_count; ++pos) {412 if (ioqueue->connecting_keys[pos] == key) {413 erase_connecting_socket(ioqueue, pos);414 break;415 }416 }417 key->connecting = 0;418 pj_lock_release(ioqueue->lock);419 }420 #endif421 if (key->hnd_type == HND_IS_FILE) {422 CloseHandle(key->hnd);423 }424 return PJ_SUCCESS;425 }426 398 427 399 /* … … 450 422 } 451 423 452 /* 453 * pj_ioqueue_poll() 454 * 455 * Poll for events. 456 */ 457 PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioqueue, const pj_time_val *timeout) 458 { 459 DWORD dwMsec, dwBytesTransfered, dwKey; 424 425 426 /* 427 * Internal function to poll the I/O Completion Port, execute callback, 428 * and return the key and bytes transfered of the last operation. 429 */ 430 static pj_bool_t poll_iocp( HANDLE hIocp, DWORD dwTimeout, 431 pj_ssize_t *p_bytes, pj_ioqueue_key_t **p_key ) 432 { 433 DWORD dwBytesTransfered, dwKey; 460 434 generic_overlapped *pOv; 461 435 pj_ioqueue_key_t *key; 462 int connect_count;463 436 pj_ssize_t size_status = -1; 464 BOOL rcGetQueued;; 465 466 PJ_ASSERT_RETURN(ioqueue, -PJ_EINVAL); 467 468 /* Check the connecting array. */ 469 #if PJ_HAS_TCP 470 connect_count = check_connecting(ioqueue); 471 #endif 472 473 /* Calculate miliseconds timeout for GetQueuedCompletionStatus */ 474 dwMsec = timeout ? timeout->sec*1000 + timeout->msec : INFINITE; 437 BOOL rcGetQueued; 475 438 476 439 /* Poll for completion status. */ 477 rcGetQueued = GetQueuedCompletionStatus( ioqueue->iocp, &dwBytesTransfered,440 rcGetQueued = GetQueuedCompletionStatus(hIocp, &dwBytesTransfered, 478 441 &dwKey, (OVERLAPPED**)&pOv, 479 dw Msec);442 dwTimeout); 480 443 481 444 /* The return value is: … … 488 451 key = (pj_ioqueue_key_t*)dwKey; 489 452 size_status = dwBytesTransfered; 453 454 /* Report to caller regardless */ 455 if (p_bytes) 456 *p_bytes = size_status; 457 if (p_key) 458 *p_key = key; 459 460 /* If size_status is POST_QUIT_LEN, mark the key as quitting */ 461 if (size_status == POST_QUIT_LEN) { 462 key->has_quit_signal = 1; 463 return PJ_TRUE; 464 } 465 466 /* We shouldn't call callbacks if key is quitting. 467 * But this should have been taken care by unregister function 468 * (the unregister function should have cleared out the callbacks) 469 */ 470 471 /* Carry out the callback */ 490 472 switch (pOv->operation) { 491 473 case PJ_IOQUEUE_OP_READ: … … 523 505 break; 524 506 } 525 return connect_count+1;507 return PJ_TRUE; 526 508 } 527 509 528 510 /* No event was queued. */ 529 return connect_count; 511 return PJ_FALSE; 512 } 513 514 /* 515 * pj_ioqueue_unregister() 516 */ 517 PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key ) 518 { 519 pj_ssize_t polled_len; 520 pj_ioqueue_key_t *polled_key; 521 generic_overlapped ov; 522 BOOL rc; 523 524 PJ_ASSERT_RETURN(key, PJ_EINVAL); 525 526 #if PJ_HAS_TCP 527 if (key->connecting) { 528 unsigned pos; 529 pj_ioqueue_t *ioqueue; 530 531 ioqueue = key->ioqueue; 532 533 /* Erase from connecting_handles */ 534 pj_lock_acquire(ioqueue->lock); 535 for (pos=0; pos < ioqueue->connecting_count; ++pos) { 536 if (ioqueue->connecting_keys[pos] == key) { 537 erase_connecting_socket(ioqueue, pos); 538 break; 539 } 540 } 541 key->connecting = 0; 542 pj_lock_release(ioqueue->lock); 543 } 544 #endif 545 546 547 /* Unregistering handle from IOCP is pretty tricky. 548 * 549 * Even after the socket has been closed, GetQueuedCompletionStatus 550 * may still return events for the handle. This will likely to 551 * cause crash in pjlib, because the key associated with the handle 552 * most likely will have been destroyed. 553 * 554 * The solution is to poll the IOCP until we're sure that there are 555 * no further events for the handle. 556 */ 557 558 /* Clear up callbacks for the key. 559 * We don't want the callback to be called for this key. 560 */ 561 key->cb.on_read_complete = NULL; 562 key->cb.on_write_complete = NULL; 563 key->cb.on_accept_complete = NULL; 564 key->cb.on_connect_complete = NULL; 565 566 /* Init overlapped struct */ 567 pj_memset(&ov, 0, sizeof(ov)); 568 ov.operation = PJ_IOQUEUE_OP_READ; 569 570 /* Post queued completion status with a special length. */ 571 rc = PostQueuedCompletionStatus( key->ioqueue->iocp, (DWORD)POST_QUIT_LEN, 572 (DWORD)key, &ov.overlapped); 573 574 /* Poll IOCP until has_quit_signal is set in the key. 575 * The has_quit_signal flag is set in poll_iocp() when POST_QUIT_LEN 576 * is detected. We need to have this flag because POST_QUIT_LEN may be 577 * detected by other threads. 578 */ 579 do { 580 polled_len = 0; 581 polled_key = NULL; 582 583 rc = poll_iocp(key->ioqueue->iocp, 0, &polled_len, &polled_key); 584 585 } while (rc && !key->has_quit_signal); 586 587 588 /* Close handle if this is a file. */ 589 if (key->hnd_type == HND_IS_FILE) { 590 CloseHandle(key->hnd); 591 } 592 593 return PJ_SUCCESS; 594 } 595 596 /* 597 * pj_ioqueue_poll() 598 * 599 * Poll for events. 600 */ 601 PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioqueue, const pj_time_val *timeout) 602 { 603 DWORD dwMsec; 604 int connect_count = 0; 605 pj_bool_t has_event; 606 607 PJ_ASSERT_RETURN(ioqueue, -PJ_EINVAL); 608 609 /* Check the connecting array. */ 610 #if PJ_HAS_TCP 611 connect_count = check_connecting(ioqueue); 612 #endif 613 614 /* Calculate miliseconds timeout for GetQueuedCompletionStatus */ 615 dwMsec = timeout ? timeout->sec*1000 + timeout->msec : INFINITE; 616 617 /* Poll for completion status. */ 618 has_event = poll_iocp(ioqueue->iocp, dwMsec, NULL, NULL); 619 620 /* Return number of events. */ 621 return connect_count + has_event; 530 622 } 531 623
Note: See TracChangeset
for help on using the changeset viewer.