aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/llthread.c139
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
441static 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
453static int llthread_detach(llthread_t *this);
454
455static int llthread_join(llthread_t *this, join_timeout_t timeout);
456
442static llthread_t *llthread_new() { 457static 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
466static void llthread_destroy(llthread_t *this) { 481static 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
485static int llthread_detach(llthread_t *this){ 518static 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 */
504static int llthread_start(llthread_t *this, int start_detached, int join_lua) { 544static 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
533static int llthread_join(llthread_t *this, join_timeout_t timeout) { 573static 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
574static llthread_t *llthread_create(lua_State *L, const char *code, size_t code_len) { 620static 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
613static int l_llthread_delete(lua_State *L) { 659static 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}