diff options
Diffstat (limited to 'src/llthread.c')
-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 | } |