diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/llthread.c | 95 |
1 files changed, 68 insertions, 27 deletions
diff --git a/src/llthread.c b/src/llthread.c index 0596b2a..b61bf11 100644 --- a/src/llthread.c +++ b/src/llthread.c | |||
| @@ -289,6 +289,7 @@ static int fail(lua_State *L, const char *msg){ | |||
| 289 | #define TSTATE_STARTED (flags_t)1<<0 | 289 | #define TSTATE_STARTED (flags_t)1<<0 |
| 290 | #define TSTATE_DETACHED (flags_t)1<<1 | 290 | #define TSTATE_DETACHED (flags_t)1<<1 |
| 291 | #define TSTATE_JOINED (flags_t)1<<2 | 291 | #define TSTATE_JOINED (flags_t)1<<2 |
| 292 | #define FLAG_JOIN_LUA (flags_t)1<<3 | ||
| 292 | 293 | ||
| 293 | /*At leas one flag*/ | 294 | /*At leas one flag*/ |
| 294 | #define FLAG_IS_SET(O, F) (O->flags & (flags_t)(F)) | 295 | #define FLAG_IS_SET(O, F) (O->flags & (flags_t)(F)) |
| @@ -397,7 +398,7 @@ static OS_THREAD_RETURT llthread_child_thread_run(void *arg) { | |||
| 397 | } | 398 | } |
| 398 | 399 | ||
| 399 | /* if thread is detached, then destroy the child state. */ | 400 | /* if thread is detached, then destroy the child state. */ |
| 400 | if(FLAG_IS_SET(this, TSTATE_DETACHED)) { | 401 | if(!FLAG_IS_SET(this, FLAG_JOIN_LUA)) { |
| 401 | /* thread is detached, so it must clean-up the child state. */ | 402 | /* thread is detached, so it must clean-up the child state. */ |
| 402 | llthread_child_destroy(this); | 403 | llthread_child_destroy(this); |
| 403 | this = NULL; | 404 | this = NULL; |
| @@ -450,7 +451,8 @@ static void llthread_destroy(llthread_t *this) { | |||
| 450 | * we have joined the thread. | 451 | * we have joined the thread. |
| 451 | */ | 452 | */ |
| 452 | if(FLAG_IS_SET(this, TSTATE_JOINED)||(this->flags == TSTATE_NONE)) { | 453 | if(FLAG_IS_SET(this, TSTATE_JOINED)||(this->flags == TSTATE_NONE)) { |
| 453 | llthread_cleanup_child(this); | 454 | if(FLAG_IS_SET(this, FLAG_JOIN_LUA)) |
| 455 | llthread_cleanup_child(this); | ||
| 454 | } | 456 | } |
| 455 | FREE_STRUCT(this); | 457 | FREE_STRUCT(this); |
| 456 | } | 458 | } |
| @@ -463,12 +465,33 @@ static int llthread_push_results(lua_State *L, llthread_child_t *child, int idx, | |||
| 463 | return llthread_copy_values(child->L, L, idx, top, 0 /* is_arg */); | 465 | return llthread_copy_values(child->L, L, idx, top, 0 /* is_arg */); |
| 464 | } | 466 | } |
| 465 | 467 | ||
| 466 | static int llthread_start(llthread_t *this, int start_detached) { | 468 | static int llthread_detach(llthread_t *this){ |
| 469 | int rc = 0; | ||
| 470 | this->child = NULL; | ||
| 471 | FLAG_SET(this, TSTATE_DETACHED); | ||
| 472 | FLAG_UNSET(this, FLAG_JOIN_LUA); | ||
| 473 | #ifdef USE_PTHREAD | ||
| 474 | rc = pthread_detach(this->thread); | ||
| 475 | #endif | ||
| 476 | return rc; | ||
| 477 | } | ||
| 478 | |||
| 479 | /* | detached | join_lua || return values | which thread | gc calls | detach on | | ||
| 480 | | | || thread:join() | closes lua state | | | | ||
| 481 | * ------------------------------------------------------------------------------------- | ||
| 482 | * | false | falas || <NONE> | child | <NONE> | <NEVER> | | ||
| 483 | * *| false | true || Lua values | parent | join | <NEVER> | | ||
| 484 | * *| true | false || <ERROR> | child | <NONE> | start | | ||
| 485 | * | true | true || <NONE> | parent | detach | gc | | ||
| 486 | * ------------------------------------------------------------------------------------- | ||
| 487 | * * llthread behavior. | ||
| 488 | */ | ||
| 489 | static int llthread_start(llthread_t *this, int start_detached, int join_lua) { | ||
| 467 | llthread_child_t *child = this->child; | 490 | llthread_child_t *child = this->child; |
| 468 | int rc = 0; | 491 | int rc = 0; |
| 469 | 492 | ||
| 470 | if(start_detached){ | 493 | if(join_lua){ /*child does not close lua_State*/ |
| 471 | FLAG_SET(child, TSTATE_DETACHED); | 494 | FLAG_SET(child, FLAG_JOIN_LUA); |
| 472 | } | 495 | } |
| 473 | 496 | ||
| 474 | #ifndef USE_PTHREAD | 497 | #ifndef USE_PTHREAD |
| @@ -482,12 +505,10 @@ static int llthread_start(llthread_t *this, int start_detached) { | |||
| 482 | 505 | ||
| 483 | if(rc == 0) { | 506 | if(rc == 0) { |
| 484 | FLAG_SET(this, TSTATE_STARTED); | 507 | FLAG_SET(this, TSTATE_STARTED); |
| 485 | if(start_detached) { | 508 | if(join_lua) FLAG_SET(this, FLAG_JOIN_LUA); |
| 486 | FLAG_SET(this, TSTATE_DETACHED); | 509 | if(start_detached) FLAG_SET(this, TSTATE_DETACHED); |
| 487 | this->child = NULL; | 510 | if((start_detached)&&(!join_lua)){ |
| 488 | #ifdef USE_PTHREAD | 511 | rc = llthread_detach(this); |
| 489 | rc = pthread_detach(this->thread); | ||
| 490 | #endif | ||
| 491 | } | 512 | } |
| 492 | } | 513 | } |
| 493 | 514 | ||
| @@ -523,7 +544,7 @@ static int llthread_join(llthread_t *this, join_timeout_t timeout) { | |||
| 523 | return rc; | 544 | return rc; |
| 524 | } | 545 | } |
| 525 | 546 | ||
| 526 | // @todo use pthread_tryjoin_np to support timeout | 547 | /* @todo use pthread_tryjoin_np to support timeout */ |
| 527 | 548 | ||
| 528 | /* then join the thread. */ | 549 | /* then join the thread. */ |
| 529 | rc = pthread_join(this->thread, NULL); | 550 | rc = pthread_join(this->thread, NULL); |
| @@ -582,17 +603,25 @@ static int l_llthread_delete(lua_State *L) { | |||
| 582 | /*already exists*/ | 603 | /*already exists*/ |
| 583 | if(this == NULL) return 0; | 604 | if(this == NULL) return 0; |
| 584 | 605 | ||
| 585 | /* if the thread has been started and has not been detached/joined. */ | 606 | do{/* join the thread. */ |
| 586 | if( FLAG_IS_SET(this, TSTATE_STARTED) && | 607 | if(!FLAG_IS_SET(this, TSTATE_STARTED)) break; |
| 587 | !FLAG_IS_SET(this, (TSTATE_DETACHED|TSTATE_JOINED)) | 608 | if( FLAG_IS_SET(this, TSTATE_JOINED)) break; |
| 588 | ){ | 609 | |
| 589 | /* then join the thread. */ | 610 | if(FLAG_IS_SET(this, TSTATE_DETACHED)){ |
| 590 | llthread_child_t *child = this->child; | 611 | if(FLAG_IS_SET(this, FLAG_JOIN_LUA)){ |
| 591 | llthread_join(this, INFINITE_JOIN_TIMEOUT); | 612 | llthread_detach(this); |
| 592 | if(child && child->status != 0) { | 613 | } |
| 593 | llthread_log(child->L, "Error from non-joined thread: ", lua_tostring(child->L, -1)); | 614 | break; |
| 594 | } | 615 | } |
| 595 | } | 616 | |
| 617 | { /* @todo log warning about lost thread for debug? */ | ||
| 618 | llthread_child_t *child = this->child; | ||
| 619 | llthread_join(this, INFINITE_JOIN_TIMEOUT); | ||
| 620 | if(child && child->status != 0) { | ||
| 621 | llthread_log(child->L, "Error from non-joined thread: ", lua_tostring(child->L, -1)); | ||
| 622 | } | ||
| 623 | } | ||
| 624 | }while(0); | ||
| 596 | 625 | ||
| 597 | llthread_destroy(this); | 626 | llthread_destroy(this); |
| 598 | *pthis = NULL; | 627 | *pthis = NULL; |
| @@ -603,13 +632,16 @@ static int l_llthread_delete(lua_State *L) { | |||
| 603 | static int l_llthread_start(lua_State *L) { | 632 | static int l_llthread_start(lua_State *L) { |
| 604 | llthread_t *this = l_llthread_at(L, 1); | 633 | llthread_t *this = l_llthread_at(L, 1); |
| 605 | int start_detached = lua_toboolean(L, 2); | 634 | int start_detached = lua_toboolean(L, 2); |
| 606 | int rc; | 635 | int join_lua, rc; |
| 636 | |||
| 637 | if(!lua_isnone(L, 3)) join_lua = lua_toboolean(L, 3); | ||
| 638 | else join_lua = start_detached ? 0 : 1; | ||
| 607 | 639 | ||
| 608 | if(this->flags != TSTATE_NONE) { | 640 | if(this->flags != TSTATE_NONE) { |
| 609 | return fail(L, "Thread already started."); | 641 | return fail(L, "Thread already started."); |
| 610 | } | 642 | } |
| 611 | 643 | ||
| 612 | rc = llthread_start(this, start_detached); | 644 | rc = llthread_start(this, start_detached, join_lua); |
| 613 | if(rc != 0) { | 645 | if(rc != 0) { |
| 614 | char buf[ERROR_LEN]; | 646 | char buf[ERROR_LEN]; |
| 615 | strerror_r(errno, buf, ERROR_LEN); | 647 | strerror_r(errno, buf, ERROR_LEN); |
| @@ -628,7 +660,7 @@ static int l_llthread_join(lua_State *L) { | |||
| 628 | if(!FLAG_IS_SET(this, TSTATE_STARTED )) { | 660 | if(!FLAG_IS_SET(this, TSTATE_STARTED )) { |
| 629 | return fail(L, "Can't join a thread that hasn't be started."); | 661 | return fail(L, "Can't join a thread that hasn't be started."); |
| 630 | } | 662 | } |
| 631 | if( FLAG_IS_SET(this, TSTATE_DETACHED)) { | 663 | if( FLAG_IS_SET(this, TSTATE_DETACHED) && !FLAG_IS_SET(this, FLAG_JOIN_LUA)) { |
| 632 | return fail(L, "Can't join a thread that has been detached."); | 664 | return fail(L, "Can't join a thread that has been detached."); |
| 633 | } | 665 | } |
| 634 | if( FLAG_IS_SET(this, TSTATE_JOINED )) { | 666 | if( FLAG_IS_SET(this, TSTATE_JOINED )) { |
| @@ -638,9 +670,17 @@ static int l_llthread_join(lua_State *L) { | |||
| 638 | /* join the thread. */ | 670 | /* join the thread. */ |
| 639 | rc = llthread_join(this, luaL_optint(L, 2, INFINITE_JOIN_TIMEOUT)); | 671 | rc = llthread_join(this, luaL_optint(L, 2, INFINITE_JOIN_TIMEOUT)); |
| 640 | 672 | ||
| 641 | /* Push all results after the Lua code. */ | ||
| 642 | if(child && FLAG_IS_SET(this, TSTATE_JOINED)) { | 673 | if(child && FLAG_IS_SET(this, TSTATE_JOINED)) { |
| 643 | int top; | 674 | int top; |
| 675 | |||
| 676 | if(!FLAG_IS_SET(this, FLAG_JOIN_LUA)){ | ||
| 677 | /*child lua state has been destroyed by child thread*/ | ||
| 678 | /*@todo return thread exit code*/ | ||
| 679 | lua_pushnumber(L, 0); | ||
| 680 | return 1; | ||
| 681 | } | ||
| 682 | |||
| 683 | /* copy values from child lua state */ | ||
| 644 | if(child->status != 0) { | 684 | if(child->status != 0) { |
| 645 | const char *err_msg = lua_tostring(child->L, -1); | 685 | const char *err_msg = lua_tostring(child->L, -1); |
| 646 | lua_pushboolean(L, 0); | 686 | lua_pushboolean(L, 0); |
| @@ -652,12 +692,13 @@ static int l_llthread_join(lua_State *L) { | |||
| 652 | /* return results to parent thread. */ | 692 | /* return results to parent thread. */ |
| 653 | llthread_push_results(L, child, 2, top); | 693 | llthread_push_results(L, child, 2, top); |
| 654 | } | 694 | } |
| 695 | |||
| 655 | llthread_cleanup_child(this); | 696 | llthread_cleanup_child(this); |
| 656 | return top; | 697 | return top; |
| 657 | } | 698 | } |
| 658 | 699 | ||
| 659 | if( rc == JOIN_ETIMEDOUT ){ | 700 | if( rc == JOIN_ETIMEDOUT ){ |
| 660 | lua_pushboolean(L, 0); | 701 | lua_pushnil(L); |
| 661 | lua_pushstring(L, "timeout"); | 702 | lua_pushstring(L, "timeout"); |
| 662 | return 2; | 703 | return 2; |
| 663 | } | 704 | } |
