diff options
| author | moteus <mimir@newmail.ru> | 2013-12-27 14:32:10 +0400 |
|---|---|---|
| committer | moteus <mimir@newmail.ru> | 2013-12-27 14:32:10 +0400 |
| commit | bccb6bef9d7eb56eece7efa96524a5fea1eb8d73 (patch) | |
| tree | 04ddfe1ceade2123ed4a5f3a382e52a6b4e4bf3f | |
| parent | 1b81ddc1a8d19ba09d7e61d0d9d841993d7187fb (diff) | |
| download | lua-llthreads2-bccb6bef9d7eb56eece7efa96524a5fea1eb8d73.tar.gz lua-llthreads2-bccb6bef9d7eb56eece7efa96524a5fea1eb8d73.tar.bz2 lua-llthreads2-bccb6bef9d7eb56eece7efa96524a5fea1eb8d73.zip | |
Fix. child struct for start(true, true) should be destroyed by child thread.
Fix. thread:join(0) in pthread should call pthread_join to free pthread_t struct.
Code refactoring.
| -rw-r--r-- | src/llthread.c | 139 |
1 files changed, 78 insertions, 61 deletions
diff --git a/src/llthread.c b/src/llthread.c index 0ff39d7..53a25b8 100644 --- a/src/llthread.c +++ b/src/llthread.c | |||
| @@ -290,7 +290,7 @@ static int fail(lua_State *L, const char *msg){ | |||
| 290 | #define TSTATE_JOINED (flags_t)1<<2 | 290 | #define TSTATE_JOINED (flags_t)1<<2 |
| 291 | #define FLAG_JOIN_LUA (flags_t)1<<3 | 291 | #define FLAG_JOIN_LUA (flags_t)1<<3 |
| 292 | 292 | ||
| 293 | /*At leas one flag*/ | 293 | /*At least one flag*/ |
| 294 | #define FLAG_IS_SET(O, F) (O->flags & (flags_t)(F)) | 294 | #define FLAG_IS_SET(O, F) (O->flags & (flags_t)(F)) |
| 295 | /*All flags*/ | 295 | /*All flags*/ |
| 296 | #define FLAGS_IS_SET(O, F) ((F) == FLAG_IS_SET(O, F)) | 296 | #define FLAGS_IS_SET(O, F) ((F) == FLAG_IS_SET(O, F)) |
| @@ -414,8 +414,7 @@ static OS_THREAD_RETURN llthread_child_thread_run(void *arg) { | |||
| 414 | llthread_log(L, "Error from thread: ", lua_tostring(L, -1)); | 414 | llthread_log(L, "Error from thread: ", lua_tostring(L, -1)); |
| 415 | } | 415 | } |
| 416 | 416 | ||
| 417 | /* if thread is detached, then destroy the child state. */ | 417 | if(FLAG_IS_SET(this, TSTATE_DETACHED) || !FLAG_IS_SET(this, FLAG_JOIN_LUA)) { |
| 418 | if(!FLAG_IS_SET(this, FLAG_JOIN_LUA)) { | ||
| 419 | /* thread is detached, so it must clean-up the child state. */ | 418 | /* thread is detached, so it must clean-up the child state. */ |
| 420 | llthread_child_destroy(this); | 419 | llthread_child_destroy(this); |
| 421 | this = NULL; | 420 | this = NULL; |
| @@ -439,6 +438,22 @@ static OS_THREAD_RETURN llthread_child_thread_run(void *arg) { | |||
| 439 | 438 | ||
| 440 | //{ llthread | 439 | //{ llthread |
| 441 | 440 | ||
| 441 | static void llthread_validate(llthread_t *this){ | ||
| 442 | if(!FLAGS_IS_SET(this, TSTATE_STARTED)){ | ||
| 443 | assert(!FLAGS_IS_SET(this, TSTATE_DETACHED)); | ||
| 444 | assert(!FLAGS_IS_SET(this, TSTATE_JOINED)); | ||
| 445 | } | ||
| 446 | else{ | ||
| 447 | if(FLAGS_IS_SET(this, TSTATE_DETACHED)){ | ||
| 448 | if(FLAGS_IS_SET(this, FLAG_JOIN_LUA)) assert(this->child == NULL); | ||
| 449 | } | ||
| 450 | } | ||
| 451 | } | ||
| 452 | |||
| 453 | static int llthread_detach(llthread_t *this); | ||
| 454 | |||
| 455 | static int llthread_join(llthread_t *this, join_timeout_t timeout); | ||
| 456 | |||
| 442 | static llthread_t *llthread_new() { | 457 | static llthread_t *llthread_new() { |
| 443 | llthread_t *this = ALLOC_STRUCT(llthread_t); | 458 | llthread_t *this = ALLOC_STRUCT(llthread_t); |
| 444 | if(!this) return NULL; | 459 | if(!this) return NULL; |
| @@ -464,13 +479,31 @@ static void llthread_cleanup_child(llthread_t *this) { | |||
| 464 | } | 479 | } |
| 465 | 480 | ||
| 466 | static void llthread_destroy(llthread_t *this) { | 481 | static void llthread_destroy(llthread_t *this) { |
| 467 | /* We still own the child thread object iff the thread was not started or | 482 | do{ |
| 468 | * we have joined the thread. | 483 | if(!FLAG_IS_SET(this, TSTATE_STARTED)){ |
| 469 | */ | ||
| 470 | if(FLAG_IS_SET(this, TSTATE_JOINED)||(this->flags == TSTATE_NONE)) { | ||
| 471 | if(FLAG_IS_SET(this, FLAG_JOIN_LUA)) | ||
| 472 | llthread_cleanup_child(this); | 484 | llthread_cleanup_child(this); |
| 473 | } | 485 | break; |
| 486 | } | ||
| 487 | if(!FLAG_IS_SET(this, FLAG_JOIN_LUA)) break; | ||
| 488 | if( FLAG_IS_SET(this, TSTATE_DETACHED)){ | ||
| 489 | llthread_detach(this); | ||
| 490 | break; | ||
| 491 | } | ||
| 492 | |||
| 493 | if(!FLAG_IS_SET(this, TSTATE_JOINED)){ | ||
| 494 | /* @todo log warning about lost thread object for debug? */ | ||
| 495 | llthread_child_t *child = this->child; | ||
| 496 | llthread_join(this, INFINITE_JOIN_TIMEOUT); | ||
| 497 | if(child && child->status != 0) { | ||
| 498 | /*@fixme remove redundant log*/ | ||
| 499 | llthread_log(child->L, "Error from non-joined thread: ", lua_tostring(child->L, -1)); | ||
| 500 | } | ||
| 501 | } | ||
| 502 | |||
| 503 | assert(FLAG_IS_SET(this, TSTATE_JOINED)); | ||
| 504 | llthread_cleanup_child(this); | ||
| 505 | }while(0); | ||
| 506 | |||
| 474 | FREE_STRUCT(this); | 507 | FREE_STRUCT(this); |
| 475 | } | 508 | } |
| 476 | 509 | ||
| @@ -484,23 +517,30 @@ static int llthread_push_results(lua_State *L, llthread_child_t *child, int idx, | |||
| 484 | 517 | ||
| 485 | static int llthread_detach(llthread_t *this){ | 518 | static int llthread_detach(llthread_t *this){ |
| 486 | int rc = 0; | 519 | int rc = 0; |
| 520 | |||
| 521 | assert(FLAGS_IS_SET(this, TSTATE_STARTED)); | ||
| 522 | |||
| 487 | this->child = NULL; | 523 | this->child = NULL; |
| 488 | #ifdef USE_PTHREAD | 524 | #ifdef USE_PTHREAD |
| 489 | rc = pthread_detach(this->thread); | 525 | rc = pthread_detach(this->thread); |
| 526 | #else | ||
| 527 | assert(this->thread != INVALID_THREAD); | ||
| 528 | CloseHandle(this->thread); | ||
| 529 | this->thread = INVALID_THREAD; | ||
| 490 | #endif | 530 | #endif |
| 491 | return rc; | 531 | return rc; |
| 492 | } | 532 | } |
| 493 | 533 | ||
| 494 | /* | detached | join_lua || return values | which thread | gc calls | detach on | | 534 | /* | detached | join_lua || return values | which thread | gc calls | detach on | |
| 495 | | | || thread:join() | closes lua state | | | | 535 | * | | || thread:join() | closes lua state | | | |
| 496 | * ------------------------------------------------------------------------------------- | 536 | * ------------------------------------------------------------------------------------- |
| 497 | * | false | falas || <NONE> | child | <NONE> | <NEVER> | | 537 | * | false | falas || <NONE> | child | <NONE> | <NEVER> | |
| 498 | * *| false | true || Lua values | parent | join | <NEVER> | | 538 | * *| false | true || Lua values | parent | join | <NEVER> | |
| 499 | * *| true | false || <ERROR> | child | <NONE> | start | | 539 | * *| true | false || <ERROR> | child | <NONE> | start | |
| 500 | * | true | true || <NONE> | parent | detach | gc | | 540 | * | true | true || <NONE> | child | detach | gc | |
| 501 | * ------------------------------------------------------------------------------------- | 541 | * ------------------------------------------------------------------------------------- |
| 502 | * * llthread behavior. | 542 | * * llthread behavior. |
| 503 | */ | 543 | */ |
| 504 | static int llthread_start(llthread_t *this, int start_detached, int join_lua) { | 544 | static int llthread_start(llthread_t *this, int start_detached, int join_lua) { |
| 505 | llthread_child_t *child = this->child; | 545 | llthread_child_t *child = this->child; |
| 506 | int rc = 0; | 546 | int rc = 0; |
| @@ -531,9 +571,12 @@ static int llthread_start(llthread_t *this, int start_detached, int join_lua) { | |||
| 531 | } | 571 | } |
| 532 | 572 | ||
| 533 | static int llthread_join(llthread_t *this, join_timeout_t timeout) { | 573 | static int llthread_join(llthread_t *this, join_timeout_t timeout) { |
| 574 | if(FLAG_IS_SET(this, TSTATE_JOINED)){ | ||
| 575 | return JOIN_OK; | ||
| 576 | } else{ | ||
| 534 | #ifndef USE_PTHREAD | 577 | #ifndef USE_PTHREAD |
| 535 | DWORD ret = 0; | 578 | DWORD ret = 0; |
| 536 | if(INVALID_THREAD == this->thread) return 0; | 579 | if(INVALID_THREAD == this->thread) return JOIN_OK; |
| 537 | ret = WaitForSingleObject( this->thread, timeout ); | 580 | ret = WaitForSingleObject( this->thread, timeout ); |
| 538 | if( ret == WAIT_OBJECT_0){ /* Destroy the thread object. */ | 581 | if( ret == WAIT_OBJECT_0){ /* Destroy the thread object. */ |
| 539 | CloseHandle( this->thread ); | 582 | CloseHandle( this->thread ); |
| @@ -550,16 +593,18 @@ static int llthread_join(llthread_t *this, join_timeout_t timeout) { | |||
| 550 | if(timeout == 0){ | 593 | if(timeout == 0){ |
| 551 | rc = pthread_kill(this->thread, 0); | 594 | rc = pthread_kill(this->thread, 0); |
| 552 | if(rc == 0){ /* still alive */ | 595 | if(rc == 0){ /* still alive */ |
| 553 | rc = JOIN_ETIMEDOUT; | 596 | return JOIN_ETIMEDOUT; |
| 554 | } | 597 | } |
| 555 | if(rc == ESRCH){ /*thread dead*/ | 598 | |
| 556 | FLAG_SET(this, TSTATE_JOINED); | 599 | if(rc != ESRCH){ |
| 557 | rc = JOIN_OK; | 600 | /*@fixme what else it can be ?*/ |
| 601 | return rc; | ||
| 558 | } | 602 | } |
| 559 | return rc; | 603 | |
| 604 | /*thread dead so we call join to free pthread_t struct */ | ||
| 560 | } | 605 | } |
| 561 | 606 | ||
| 562 | /* @todo use pthread_tryjoin_np to support timeout */ | 607 | /* @todo use pthread_tryjoin_np/pthread_timedjoin_np to support timeout */ |
| 563 | 608 | ||
| 564 | /* then join the thread. */ | 609 | /* then join the thread. */ |
| 565 | rc = pthread_join(this->thread, NULL); | 610 | rc = pthread_join(this->thread, NULL); |
| @@ -569,6 +614,7 @@ static int llthread_join(llthread_t *this, join_timeout_t timeout) { | |||
| 569 | } | 614 | } |
| 570 | return rc; | 615 | return rc; |
| 571 | #endif | 616 | #endif |
| 617 | } | ||
| 572 | } | 618 | } |
| 573 | 619 | ||
| 574 | static llthread_t *llthread_create(lua_State *L, const char *code, size_t code_len) { | 620 | static llthread_t *llthread_create(lua_State *L, const char *code, size_t code_len) { |
| @@ -612,34 +658,9 @@ static llthread_t *l_llthread_at (lua_State *L, int i) { | |||
| 612 | 658 | ||
| 613 | static int l_llthread_delete(lua_State *L) { | 659 | static int l_llthread_delete(lua_State *L) { |
| 614 | llthread_t **pthis = (llthread_t **)lutil_checkudatap (L, 1, LLTHREAD_T); | 660 | llthread_t **pthis = (llthread_t **)lutil_checkudatap (L, 1, LLTHREAD_T); |
| 615 | llthread_t *this; | ||
| 616 | luaL_argcheck (L, pthis != NULL, 1, "thread expected"); | 661 | luaL_argcheck (L, pthis != NULL, 1, "thread expected"); |
| 617 | this = *pthis; | 662 | if(*pthis == NULL) return 0; |
| 618 | 663 | llthread_destroy(*pthis); | |
| 619 | /*already exists*/ | ||
| 620 | if(this == NULL) return 0; | ||
| 621 | |||
| 622 | do{/* join the thread. */ | ||
| 623 | if(!FLAG_IS_SET(this, TSTATE_STARTED)) break; | ||
| 624 | if( FLAG_IS_SET(this, TSTATE_JOINED)) break; | ||
| 625 | |||
| 626 | if(FLAG_IS_SET(this, TSTATE_DETACHED)){ | ||
| 627 | if(FLAG_IS_SET(this, FLAG_JOIN_LUA)){ | ||
| 628 | llthread_detach(this); | ||
| 629 | } | ||
| 630 | break; | ||
| 631 | } | ||
| 632 | |||
| 633 | { /* @todo log warning about lost thread for debug? */ | ||
| 634 | llthread_child_t *child = this->child; | ||
| 635 | llthread_join(this, INFINITE_JOIN_TIMEOUT); | ||
| 636 | if(child && child->status != 0) { | ||
| 637 | llthread_log(child->L, "Error from non-joined thread: ", lua_tostring(child->L, -1)); | ||
| 638 | } | ||
| 639 | } | ||
| 640 | }while(0); | ||
| 641 | |||
| 642 | llthread_destroy(this); | ||
| 643 | *pthis = NULL; | 664 | *pthis = NULL; |
| 644 | 665 | ||
| 645 | return 0; | 666 | return 0; |
| @@ -653,7 +674,7 @@ static int l_llthread_start(lua_State *L) { | |||
| 653 | if(!lua_isnone(L, 3)) join_lua = lua_toboolean(L, 3); | 674 | if(!lua_isnone(L, 3)) join_lua = lua_toboolean(L, 3); |
| 654 | else join_lua = start_detached ? 0 : 1; | 675 | else join_lua = start_detached ? 0 : 1; |
| 655 | 676 | ||
| 656 | if(this->flags != TSTATE_NONE) { | 677 | if(FLAG_IS_SET(this, TSTATE_STARTED)) { |
| 657 | return fail(L, "Thread already started."); | 678 | return fail(L, "Thread already started."); |
| 658 | } | 679 | } |
| 659 | 680 | ||
| @@ -714,20 +735,16 @@ static int l_llthread_join(lua_State *L) { | |||
| 714 | } | 735 | } |
| 715 | 736 | ||
| 716 | if( rc == JOIN_ETIMEDOUT ){ | 737 | if( rc == JOIN_ETIMEDOUT ){ |
| 717 | lua_pushnil(L); | 738 | return fail(L, "timeout"); |
| 718 | lua_pushstring(L, "timeout"); | ||
| 719 | return 2; | ||
| 720 | } | 739 | } |
| 721 | 740 | ||
| 722 | { | 741 | { |
| 723 | char buf[ERROR_LEN]; | 742 | char buf[ERROR_LEN]; |
| 724 | strerror_r(errno, buf, ERROR_LEN); | 743 | strerror_r(errno, buf, ERROR_LEN); |
| 725 | 744 | ||
| 726 | llthread_cleanup_child(this); | 745 | /* llthread_cleanup_child(this); */ |
| 727 | 746 | ||
| 728 | lua_pushboolean(L, 0); | 747 | return fail(L, buf); |
| 729 | lua_pushstring(L, buf); | ||
| 730 | return 2; | ||
| 731 | } | 748 | } |
| 732 | 749 | ||
| 733 | } | 750 | } |
