diff options
author | moteus <mimir@newmail.ru> | 2013-12-26 18:52:58 +0400 |
---|---|---|
committer | moteus <mimir@newmail.ru> | 2013-12-26 18:52:58 +0400 |
commit | e3fe5123a36643634e00de6a1bb940e6e1febade (patch) | |
tree | 8eecc3aa10e8c6842efe1d798758942f35f555f6 /src | |
parent | 5291caae5be68250a4d9aafa54fe2081ab2a6113 (diff) | |
download | lua-llthreads2-e3fe5123a36643634e00de6a1bb940e6e1febade.tar.gz lua-llthreads2-e3fe5123a36643634e00de6a1bb940e6e1febade.tar.bz2 lua-llthreads2-e3fe5123a36643634e00de6a1bb940e6e1febade.zip |
Add. `joinable` parameter to `start` method which control in which thread child Lua VM will be destroyed.
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 | } |